summaryrefslogtreecommitdiff
path: root/src/char_sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/char_sql')
-rw-r--r--src/char_sql/char.c8870
-rw-r--r--src/char_sql/char.h220
-rw-r--r--src/char_sql/int_guild.c4212
-rw-r--r--src/char_sql/int_guild.h70
-rw-r--r--src/char_sql/int_homun.c592
-rw-r--r--src/char_sql/int_homun.h28
-rw-r--r--src/char_sql/int_party.c1874
-rw-r--r--src/char_sql/int_party.h60
-rw-r--r--src/char_sql/int_pet.c744
-rw-r--r--src/char_sql/int_pet.h36
-rw-r--r--src/char_sql/int_storage.c758
-rw-r--r--src/char_sql/int_storage.h34
-rw-r--r--src/char_sql/inter.c1644
-rw-r--r--src/char_sql/inter.h112
-rw-r--r--src/char_sql/itemdb.c444
-rw-r--r--src/char_sql/itemdb.h86
16 files changed, 9892 insertions, 9892 deletions
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 136453e3b..a6bc9dbea 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -1,4435 +1,4435 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by Jioh L. Jung
-// TXT 1.105
-#include <sys/types.h>
-
-#ifdef _WIN32
-#include <winsock.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
-#include <time.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include "char.h"
-#include "../common/utils.h"
-#include "../common/strlib.h"
-#include "../common/showmsg.h"
-#include "itemdb.h"
-#include "inter.h"
-#include "db.h"
-#include "malloc.h"
-#include "int_guild.h"
-
-#ifndef TXT_SQL_CONVERT
-static struct dbt *char_db_;
-#endif
-char char_db[256] = "char";
-char scdata_db[256] = "sc_data";
-char cart_db[256] = "cart_inventory";
-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";
-char guild_alliance_db[256] = "guild_alliance";
-char guild_castle_db[256] = "guild_castle";
-char guild_expulsion_db[256] = "guild_expulsion";
-char guild_member_db[256] = "guild_member";
-char guild_position_db[256] = "guild_position";
-char guild_skill_db[256] = "guild_skill";
-char guild_storage_db[256] = "guild_storage";
-char party_db[256] = "party";
-char pet_db[256] = "pet";
-char friend_db[256] = "friends";
-#ifdef TXT_SQL_CONVERT
-int save_log = 0; //Have the logs be off by default when converting
-#else
-int save_log = 1;
-int db_use_sqldbs;
-int connection_ping_interval = 0;
-
-char login_db[256] = "login";
-char login_db_account_id[32] = "account_id";
-char login_db_level[32] = "level";
-
-int lowest_gm_level = 1;
-
-char *SQL_CONF_NAME = "conf/inter_athena.conf";
-
-struct mmo_map_server{
- long ip;
- short port;
- int users;
- unsigned short map[MAX_MAP_PER_SERVER];
-} server[MAX_MAP_SERVERS];
-
-int server_fd[MAX_MAP_SERVERS];
-
-int login_fd, char_fd;
-char userid[24];
-char passwd[24];
-char server_name[20];
-char wisp_server_name[NAME_LENGTH] = "Server";
-char login_ip_str[128];
-in_addr_t login_ip = 0;
-int login_port = 6900;
-char char_ip_str[128];
-in_addr_t char_ip = 0;
-char bind_ip_str[128];
-in_addr_t bind_ip = 0;
-int char_port = 6121;
-int char_maintenance = 0;
-int char_new;
-int char_new_display;
-int name_ignoring_case = 0; // 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]
-char char_name_letters[1024] = ""; // list of letters/symbols used to authorise or not a name of a character. by [Yor]
-//The following are characters that are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
-#define TRIM_CHARS "\032\t\x0A\x0D "
-int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
-int char_del_level = 0; //From which level u can delete character [Lupus]
-
-int log_char = 1; // loggin char or not [devil]
-int log_inter = 1; // loggin inter or not [devil]
-
-// Advanced subnet check [LuzZza]
-struct _subnet {
- long subnet;
- long mask;
- long char_ip;
- long map_ip;
-} subnet[16];
-
-int subnet_count = 0;
-
-char unknown_char_name[NAME_LENGTH] = "Unknown";
-char db_path[1024]="db";
-
-//These are used to aid the map server in identifying valid clients. [Skotlex]
-static int max_account_id = DEFAULT_MAX_ACCOUNT_ID, max_char_id = DEFAULT_MAX_CHAR_ID;
-static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex]
-
-struct char_session_data{
- int account_id, login_id1, login_id2,sex;
- int found_char[9];
- char email[40]; // e-mail (default: a@a.com) by [Yor]
- time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
-};
-
-#define AUTH_FIFO_SIZE 256
-struct {
- int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag,sex;
- time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
-} auth_fifo[AUTH_FIFO_SIZE];
-int auth_fifo_pos = 0;
-
-int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system)
-
-struct mmo_charstatus char_dat;
-int char_num,char_max;
-int max_connect_user = 0;
-int gm_allow_level = 99;
-int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
-int start_zeny = 0;
-int start_weapon = 1201;
-int start_armor = 2301;
-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_taekwon = MAX_FAME_LIST;
-
-// Char-server-side stored fame lists [DracoRPG]
-struct fame_list smith_fame_list[MAX_FAME_LIST];
-struct fame_list chemist_fame_list[MAX_FAME_LIST];
-struct fame_list taekwon_fame_list[MAX_FAME_LIST];
-
-// check for exit signal
-// 0 is saving complete
-// other is char_id
-unsigned int save_flag = 0;
-
-// start point (you can reset point on conf file)
-struct point start_point = { 0, 53, 111};
-
-bool char_gm_read = false;
-struct gm_account *gm_account = NULL;
-int GM_num = 0;
-
-int console = 0;
-
-//Structure for holding in memory which characters are online on the map servers connected.
-struct online_char_data {
- int account_id;
- int char_id;
- short server;
- unsigned waiting_disconnect :1;
-};
-
-struct dbt *online_char_db; //Holds all online characters.
-
-#ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
-#else
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-#endif
-
-static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data);
-
-static void * create_online_char_data(DBKey key, va_list args) {
- struct online_char_data* character;
- character = aCalloc(1, sizeof(struct online_char_data));
- character->account_id = key.i;
- character->char_id = -1;
- character->server = -1;
- return character;
-}
-
-//-------------------------------------------------
-// Set Character online/offline [Wizputer]
-//-------------------------------------------------
-
-void set_char_online(int map_id, int char_id, int account_id) {
- struct online_char_data* character;
- if ( char_id != 99 ) {
- sprintf(tmp_sql, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d'",char_db,char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- if (max_account_id < account_id || max_char_id < char_id)
- { //Notify map-server of the new max IDs [Skotlex]
- if (account_id > max_account_id)
- max_account_id = account_id;
- if (char_id > max_char_id)
- max_char_id = char_id;
- mapif_send_maxid(max_account_id, max_char_id);
- }
- }
-
- character = idb_ensure(online_char_db, account_id, create_online_char_data);
- if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id)
- {
- //char == 99 <- Character logging in, so someone has logged in while one
- //char is still on map-server, so kick him out, but don't print "error"
- //as this is normal behaviour. [Skotlex]
- if (char_id != 99)
- ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n",
- character->account_id, character->char_id, character->server, map_id, account_id, char_id);
- mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
- }
- character->char_id = (char_id==99)?-1:char_id;
- character->server = (char_id==99)?-1:map_id;
- character->waiting_disconnect = 0;
- if (char_id != 99)
- { //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it.
- struct mmo_charstatus *cp;
- cp = idb_get(char_db_,char_id);
- inter_guild_CharOnline(char_id, cp?cp->guild_id:-1);
- }
- if (login_fd > 0 && !session[login_fd]->eof)
- {
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x272b;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- }
-}
-
-void set_char_offline(int char_id, int account_id) {
- struct mmo_charstatus *cp;
- struct online_char_data* character;
-
- if ( char_id == 99 )
- sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id);
- else {
- cp = idb_get(char_db_,char_id);
- inter_guild_CharOffline(char_id, cp?cp->guild_id:-1);
- if (cp)
- idb_remove(char_db_,char_id);
-
- sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `char_id`='%d'", char_db, char_id);
-
- if (mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- if ((character = idb_get(online_char_db, account_id)) != NULL)
- { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex]
- character->char_id = -1;
- character->server = -1;
- character->waiting_disconnect = 0;
- }
-
- if (login_fd > 0 && !session[login_fd]->eof)
- {
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x272c;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- }
-}
-
-static int char_db_setoffline(DBKey key, void* data, va_list ap) {
- struct online_char_data* character = (struct online_char_data*)data;
- int server = va_arg(ap, int);
- if (server == -1) {
- character->char_id = -1;
- character->server = -1;
- character->waiting_disconnect = 0;
- } else if (character->server == server)
- character->server = -2; //In some map server that we aren't connected to.
- return 0;
-}
-
-static int char_db_kickoffline(DBKey key, void* data, va_list ap) {
- struct online_char_data* character = (struct online_char_data*)data;
- int server = va_arg(ap, int);
- if (server > -1 && character->server != server)
- return 0;
-
- //Kick out any connected characters, and set them offline as appropiate.
- if (character->server > -1)
- mapif_disconnectplayer(server_fd[character->server],
- character->account_id, character->char_id, 1);
- else if (!character->waiting_disconnect)
- set_char_offline(character->char_id, character->account_id);
- else return 0;
- return 1;
-}
-
-void set_all_offline(int id) {
- if (id < 0)
- ShowNotice("Sending all users offline.\n");
- else
- ShowNotice("Sending users of map-server %d offline.\n",id);
- online_char_db->foreach(online_char_db,char_db_kickoffline,id);
-
- if (id >= 0 || login_fd <= 0 || session[login_fd]->eof)
- return;
- //Tell login-server to also mark all our characters as offline.
- WFIFOHEAD(login_fd, 2);
- WFIFOW(login_fd,0) = 0x2737;
- WFIFOSET(login_fd,2);
-}
-
-void set_all_offline_sql(void) {
- //Set all players to 'OFFLINE'
- sprintf(tmp_sql, "UPDATE `%s` SET `online` = '0'", char_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql, "UPDATE `%s` SET `online` = '0'", guild_member_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql, "UPDATE `%s` SET `connect_member` = '0'", guild_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-}
-
-//----------------------------------------------------------------------
-// Determine if an account (id) is a GM account
-// and returns its level (or 0 if it isn't a GM account or if not found)
-//----------------------------------------------------------------------
-// Removed since nothing GM related goes on in the char server [CLOWNISIUS]
-int isGM(int account_id) {
- int i;
-
- for(i = 0; i < GM_num; i++)
- if (gm_account[i].account_id == account_id)
- return gm_account[i].level;
- return 0;
-}
-
-void read_gm_account(void) {
- if(!char_gm_read)
- return;
-
- if (gm_account != NULL)
- aFree(gm_account);
- GM_num = 0;
-
- sprintf(tmp_sql, "SELECT `%s`,`%s` FROM `%s` WHERE `%s`>='%d'",login_db_account_id,login_db_level,login_db,login_db_level,lowest_gm_level);
- if (mysql_query(&lmysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&lmysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- lsql_res = mysql_store_result(&lmysql_handle);
- if (lsql_res) {
- gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * (size_t)mysql_num_rows(lsql_res), 1);
- while ((lsql_row = mysql_fetch_row(lsql_res))) {
- gm_account[GM_num].account_id = atoi(lsql_row[0]);
- gm_account[GM_num].level = atoi(lsql_row[1]);
- GM_num++;
- }
- }
-
- mysql_free_result(lsql_res);
- mapif_send_gmaccounts();
-}
-#endif //TXT_SQL_CONVERT
-int compare_item(struct item *a, struct item *b) {
-
- if(a->id == b->id &&
- a->nameid == b->nameid &&
- a->amount == b->amount &&
- a->equip == b->equip &&
- a->identify == b->identify &&
- a->refine == b->refine &&
- a->attribute == b->attribute)
- {
- int i;
- for (i=0; i<MAX_SLOTS && a->card[i]==b->card[i]; i++);
- return (i == MAX_SLOTS);
- }
- return 0;
-}
-
-#ifndef TXT_SQL_CONVERT
-static void* create_charstatus(DBKey key, va_list args) {
- struct mmo_charstatus *cp;
- cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus));
- cp->char_id = key.i;
- return cp;
-}
-#endif //TXT_SQL_CONVERT
-int mmo_char_tosql(int char_id, struct mmo_charstatus *p){
- int i=0,j;
- int count = 0;
- int diff = 0;
- char *tmp_ptr; //Building a single query should be more efficient than running
- //multiple queries for each thing about to be saved, right? [Skotlex]
- char save_status[128]; //For displaying save information. [Skotlex]
- struct mmo_charstatus *cp;
- struct itemtmp mapitem[MAX_GUILD_STORAGE];
-
- if (char_id!=p->char_id) return 0;
-
-#ifndef TXT_SQL_CONVERT
- cp = idb_ensure(char_db_, char_id, create_charstatus);
-#else
- cp = aCalloc(1, sizeof(struct mmo_charstatus));
-#endif
-
- memset(save_status, 0, sizeof(save_status));
- diff = 0;
- //map inventory data
- for(i=0;i<MAX_INVENTORY;i++){
- if (!compare_item(&p->inventory[i], &cp->inventory[i]))
- diff = 1;
- if(p->inventory[i].nameid>0){
- mapitem[count].flag=0;
- mapitem[count].id = p->inventory[i].id;
- mapitem[count].nameid=p->inventory[i].nameid;
- mapitem[count].amount = p->inventory[i].amount;
- mapitem[count].equip = p->inventory[i].equip;
- mapitem[count].identify = p->inventory[i].identify;
- mapitem[count].refine = p->inventory[i].refine;
- mapitem[count].attribute = p->inventory[i].attribute;
- for (j=0; j<MAX_SLOTS; j++)
- mapitem[count].card[j] = p->inventory[i].card[j];
- count++;
- }
- }
- //printf("- Save item data to MySQL!\n");
- if (diff)
- if (!memitemdata_to_sql(mapitem, count, p->char_id,TABLE_INVENTORY))
- strcat(save_status, " inventory");
-
- count = 0;
- diff = 0;
-
- //map cart data
- for(i=0;i<MAX_CART;i++){
- if (!compare_item(&p->cart[i], &cp->cart[i]))
- diff = 1;
- if(p->cart[i].nameid>0){
- mapitem[count].flag=0;
- mapitem[count].id = p->cart[i].id;
- mapitem[count].nameid=p->cart[i].nameid;
- mapitem[count].amount = p->cart[i].amount;
- mapitem[count].equip = p->cart[i].equip;
- mapitem[count].identify = p->cart[i].identify;
- mapitem[count].refine = p->cart[i].refine;
- mapitem[count].attribute = p->cart[i].attribute;
- for (j=0; j<MAX_SLOTS; j++)
- mapitem[count].card[j] = p->cart[i].card[j];
- count++;
- }
- }
-
- if (diff)
- if (!memitemdata_to_sql(mapitem, count, p->char_id,TABLE_CART))
- strcat(save_status, " cart");
-#ifdef TXT_SQL_CONVERT
-{ //Insert the barebones to then update the rest.
- char t_name[NAME_LENGTH*2];
- jstrescapecpy(t_name, p->name);
- sprintf(tmp_sql, "REPLACE INTO `%s` (`account_id`, `char_num`, `name`) VALUES ('%d', '%d', '%s')",
- char_db, p->account_id, p->char_num, t_name);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " creation");
-}
-#endif
-
- if (
- (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) ||
- (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) ||
- (p->zeny != cp->zeny) ||
- (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) ||
- (p->max_hp != cp->max_hp) || (p->hp != cp->hp) ||
- (p->max_sp != cp->max_sp) || (p->sp != cp->sp) ||
- (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) ||
- (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) ||
- (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) ||
- (p->option != cp->option) ||
- (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) ||
- (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) ||
- (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
- (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom)
- )
- { //Save status
- sprintf(tmp_sql ,"UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
- "`base_exp`='%u', `job_exp`='%u', `zeny`='%d',"
- "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d',"
- "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d',"
- "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," //[orn] add homun_id (homunculus id)
- "`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'"
- " WHERE `account_id`='%d' AND `char_id` = '%d'",
- char_db, p->base_level, p->job_level,
- p->base_exp, p->job_exp, p->zeny,
- p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point,
- p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
- p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, //[orn] add homun_id (homunculus id)
- p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
- 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->account_id, p->char_id
- );
-
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " status");
- }
-
- //Values that will seldom change (to speed up saving)
- if (
- (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) ||
- (p->class_ != cp->class_) ||
- (p->partner_id != cp->partner_id) || (p->father != cp->father) ||
- (p->mother != cp->mother) || (p->child != cp->child) ||
- (p->karma != cp->karma) || (p->manner != cp->manner) ||
- (p->fame != cp->fame)
- )
- {
- sprintf(tmp_sql ,"UPDATE `%s` SET `class`='%d',"
- "`hair`='%d',`hair_color`='%d',`clothes_color`='%d',"
- "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d',"
- "`karma`='%d',`manner`='%d', `fame`='%d'"
- " WHERE `account_id`='%d' AND `char_id` = '%d'",
- char_db, p->class_,
- p->hair, p->hair_color, p->clothes_color,
- p->partner_id, p->father, p->mother, p->child,
- p->karma, p->manner, p->fame,
- p->account_id, p->char_id
- );
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " status2");
- }
-
-
- diff = 0;
-
- for(i=0;i<MAX_MEMOPOINTS;i++){
- if(p->memo_point[i].map == cp->memo_point[i].map && p->memo_point[i].x == cp->memo_point[i].x && p->memo_point[i].y == cp->memo_point[i].y)
- continue;
- diff = 1;
- break;
- }
-
- if (diff)
- { //Save memo
- //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",memo_db, p->char_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- //insert here.
- tmp_ptr = tmp_sql;
- tmp_ptr += sprintf(tmp_ptr, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db);
- count = 0;
- for(i=0;i<MAX_MEMOPOINTS;i++){
- if(p->memo_point[i].map){
- tmp_ptr += sprintf(tmp_ptr,"('%d', '%s', '%d', '%d'),",
- char_id, mapindex_id2name(p->memo_point[i].map), p->memo_point[i].x, p->memo_point[i].y);
- count++;
- }
- }
- if (count)
- { //Dangerous? Only if none of the above sprintf worked. [Skotlex]
- tmp_ptr[-1] = '\0'; //Remove the trailing comma.
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " memo");
- } else //Memo Points cleared (how is this possible?).
- strcat(save_status, " memo");
- }
-
- diff = 0;
- for(i=0;i<MAX_SKILL;i++) {
- if ((p->skill[i].lv != 0) && (p->skill[i].id == 0))
- p->skill[i].id = i; // Fix skill tree
-
- if((p->skill[i].id != cp->skill[i].id) || (p->skill[i].lv != cp->skill[i].lv) ||
- (p->skill[i].flag != cp->skill[i].flag))
- {
- diff = 1;
- break;
- }
- }
-
- if (diff)
- { //Save skills
-
- //`skill` (`char_id`, `id`, `lv`)
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",skill_db, p->char_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- tmp_ptr = tmp_sql;
- tmp_ptr += sprintf(tmp_ptr,"INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db);
- count = 0;
- //insert here.
- for(i=0;i<MAX_SKILL;i++){
- if(p->skill[i].id && p->skill[i].flag!=1)
- {
- tmp_ptr += sprintf(tmp_ptr,"('%d','%d','%d'),",
- char_id, p->skill[i].id, (p->skill[i].flag==0)?p->skill[i].lv:p->skill[i].flag-2);
- count++;
- }
- }
-
- if (count)
- {
- tmp_ptr[-1] = '\0'; //Remove trailing comma.
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " skills");
- } else //Skills removed (reset?)
- strcat(save_status, " skills");
- }
- diff = 0;
- for(i = 0; i < MAX_FRIENDS; i++){
- if(p->friends[i].char_id != cp->friends[i].char_id ||
- p->friends[i].account_id != cp->friends[i].account_id){
- diff = 1;
- break;
- }
- }
-
- if(diff == 1)
- { //Save friends
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- tmp_ptr = tmp_sql;
- tmp_ptr += sprintf(tmp_ptr, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db);
- count = 0;
- for(i = 0; i < MAX_FRIENDS; i++){
- if(p->friends[i].char_id > 0)
- {
- tmp_ptr += sprintf(tmp_ptr, "('%d','%d','%d'),", char_id, p->friends[i].account_id, p->friends[i].char_id);
- count++;
- }
- }
- if (count)
- {
- tmp_ptr[-1] = '\0'; //Remove the last comma. [Skotlex]
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else
- strcat(save_status, " friends");
- } else //Friend list cleared.
- strcat(save_status, " friends");
-
- }
-
- if (save_status[0]!='\0' && save_log)
- ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status);
-#ifndef TXT_SQL_CONVERT
- memcpy(cp, p, sizeof(struct mmo_charstatus));
-#else
- aFree(cp);
-#endif
- return 0;
-}
-
-// [Ilpalazzo-sama]
-int memitemdata_to_sql(struct itemtmp mapitem[], int count, int char_id, int tableswitch)
-{
- int i,j, flag, id;
- char *tablename;
- char selectoption[16];
- char * str_p = tmp_sql;
-
- switch (tableswitch) {
- case TABLE_INVENTORY:
- tablename = inventory_db; // no need for sprintf here as *_db are char*.
- sprintf(selectoption,"char_id");
- break;
- case TABLE_CART:
- tablename = cart_db;
- sprintf(selectoption,"char_id");
- break;
- case TABLE_STORAGE:
- tablename = storage_db;
- sprintf(selectoption,"account_id");
- break;
- case TABLE_GUILD_STORAGE:
- tablename = guild_storage_db;
- sprintf(selectoption,"guild_id");
- break;
- default:
- ShowError("Invalid table name!\n");
- return 1;
- }
-
- //=======================================mysql database data > memory===============================================
-
- str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
-
- for (j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`", j);
-
- str_p += sprintf(str_p, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, char_id);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 1;
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- while ((sql_row = mysql_fetch_row(sql_res))) {
- flag = 0;
- id = atoi(sql_row[0]);
- for(i = 0; i < count; i++) {
- if(mapitem[i].flag == 1)
- continue;
- if(mapitem[i].nameid == atoi(sql_row[1])
- && mapitem[i].card[0] == atoi(sql_row[7])
- && mapitem[i].card[2] == atoi(sql_row[9])
- && mapitem[i].card[3] == atoi(sql_row[10])
- ) { //They are the same item.
- for (j = 0; j<MAX_SLOTS && mapitem[i].card[j] == atoi(sql_row[7+j]); j++);
- if (j == MAX_SLOTS &&
- mapitem[i].amount == atoi(sql_row[2]) &&
- mapitem[i].equip == atoi(sql_row[3]) &&
- mapitem[i].identify == atoi(sql_row[4]) &&
- mapitem[i].refine == atoi(sql_row[5]) &&
- mapitem[i].attribute == atoi(sql_row[6]))
- { //Do nothing.
- } else
-//==============================================Memory data > SQL ===============================
-#ifndef TXT_SQL_CONVERT
- if(!itemdb_isequip(mapitem[i].nameid))
- { //Quick update of stackable items. Update Qty and Equip should be enough, but in case we are also updating identify
- sprintf(tmp_sql,"UPDATE `%s` SET `equip`='%d', `identify`='%d', `amount`='%d' WHERE `id`='%d' LIMIT 1",
- tablename, mapitem[i].equip, mapitem[i].identify,mapitem[i].amount, id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- } else
-#endif //TXT_SQL_CONVERT
- { //Equipment or Misc item, just update all fields.
- str_p = tmp_sql;
- str_p += sprintf(str_p,"UPDATE `%s` SET `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d'",
- tablename, mapitem[i].equip, mapitem[i].identify, mapitem[i].refine, mapitem[i].attribute);
-
- for(j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`=%d", j, mapitem[i].card[j]);
-
- str_p += sprintf(str_p,", `amount`='%d' WHERE `id`='%d' LIMIT 1",
- mapitem[i].amount, id);
-
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- flag = mapitem[i].flag = 1; //Item dealt with,
- break; //skip to next item in the db.
- }
- }
- if(!flag) { //Item not updated, remove it.
- sprintf(tmp_sql,"DELETE from `%s` where `id`='%d'", tablename, id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- mysql_free_result(sql_res);
- }
-
- for(i = 0; i < count; i++) {
- if(!mapitem[i].flag) {
- str_p = tmp_sql;
- str_p += sprintf(str_p,"INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`",
- tablename, selectoption);
- for(j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p,", `card%d`", j);
-
- str_p += sprintf(str_p,") VALUES ( '%d','%d', '%d', '%d', '%d', '%d', '%d'",
- char_id, mapitem[i].nameid, mapitem[i].amount, mapitem[i].equip, mapitem[i].identify, mapitem[i].refine,
- mapitem[i].attribute);
-
- for(j=0; j<MAX_SLOTS; j++)
- str_p +=sprintf(str_p,", '%d'",mapitem[i].card[j]);
-
- strcat(tmp_sql, ")");
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-//=====================================================================================================
-int mmo_char_fromsql(int char_id, struct mmo_charstatus *p){
- int i,j, n;
- double exp;
- char t_msg[128];
- char *str_p = tmp_sql;
- struct mmo_charstatus *cp;
-
- memset(p, 0, sizeof(struct mmo_charstatus));
- t_msg[0]= '\0';
-
- p->char_id = char_id;
- if (save_log)
- ShowInfo("Char load request (%d)\n", char_id);
- //`char`( `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, //9
- //`str`,`agi`,`vit`,`int`,`dex`,`luk`, //15
- //`max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, //21
- //`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`, //27
- //`hair`,`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, //35
- //`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`)
- //splite 2 parts. cause veeeery long SQL syntax
-
- sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
- "`str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res) {
- sql_row = mysql_fetch_row(sql_res);
- if (!sql_row)
- { //Just how does this happens? [Skotlex]
- ShowError("Requested non-existant character id: %d!\n", char_id);
- return 0;
- }
-
- p->char_id = char_id;
- p->account_id = atoi(sql_row[1]);
- p->char_num = atoi(sql_row[2]);
- strcpy(p->name, sql_row[3]);
- p->class_ = atoi(sql_row[4]);
- p->base_level = atoi(sql_row[5]);
- p->job_level = atoi(sql_row[6]);
- exp = atof(sql_row[7]);
- p->base_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
- exp = atof(sql_row[8]);
- p->job_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
- p->zeny = atoi(sql_row[9]);
- p->str = atoi(sql_row[10]);
- p->agi = atoi(sql_row[11]);
- p->vit = atoi(sql_row[12]);
- p->int_ = atoi(sql_row[13]);
- p->dex = atoi(sql_row[14]);
- p->luk = atoi(sql_row[15]);
- p->max_hp = atoi(sql_row[16]);
- p->hp = atoi(sql_row[17]);
- p->max_sp = atoi(sql_row[18]);
- p->sp = atoi(sql_row[19]);
- p->status_point = atoi(sql_row[20]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[20]);
- p->skill_point = atoi(sql_row[21]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[21]);
- //free mysql result.
- mysql_free_result(sql_res);
- strcat (t_msg, " status");
- } else
- ShowError("Load char failed (%d - table %s).\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
-
- sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_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`, `homun_id`" //[orn] homun_id
- "FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
- sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
- if (sql_row) {
-
- p->option = atoi(sql_row[0]); p->karma = atoi(sql_row[1]); p->manner = atoi(sql_row[2]);
- p->party_id = atoi(sql_row[3]); p->guild_id = atoi(sql_row[4]); p->pet_id = atoi(sql_row[5]);
-
- p->hair = atoi(sql_row[6]); p->hair_color = atoi(sql_row[7]); p->clothes_color = atoi(sql_row[8]);
- p->weapon = atoi(sql_row[9]); p->shield = atoi(sql_row[10]);
- p->head_top = atoi(sql_row[11]); p->head_mid = atoi(sql_row[12]); p->head_bottom = atoi(sql_row[13]);
- p->last_point.map = mapindex_name2id(sql_row[14]); p->last_point.x = atoi(sql_row[15]); p->last_point.y = atoi(sql_row[16]);
- p->save_point.map = mapindex_name2id(sql_row[17]); p->save_point.x = atoi(sql_row[18]); p->save_point.y = atoi(sql_row[19]);
- p->partner_id = atoi(sql_row[20]); p->father = atoi(sql_row[21]); p->mother = atoi(sql_row[22]); p->child = atoi(sql_row[23]);
- p->fame = atoi(sql_row[24]);
- p->hom_id = atoi(sql_row[25]); //[orn] homunculus id
-
- strcat (t_msg, " status2");
- } else
- ShowError("Char load failed (%d - table %s)\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
- //free mysql result.
- if (sql_res)
- mysql_free_result(sql_res);
-
- //read memo data
- //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
- sprintf(tmp_sql, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`='%d' ORDER by `memo_id`",memo_db, char_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res) {
- for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
- p->memo_point[i].map = mapindex_name2id(sql_row[0]);
- p->memo_point[i].x=atoi(sql_row[1]);
- p->memo_point[i].y=atoi(sql_row[2]);
- //i ++;
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " memo");
- }
-
- //read inventory
- //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
- str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
-
- for (j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`", j);
-
- str_p += sprintf(str_p, " FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
- p->inventory[i].id = atoi(sql_row[0]);
- p->inventory[i].nameid = atoi(sql_row[1]);
- p->inventory[i].amount = atoi(sql_row[2]);
- p->inventory[i].equip = atoi(sql_row[3]);
- p->inventory[i].identify = atoi(sql_row[4]);
- p->inventory[i].refine = atoi(sql_row[5]);
- p->inventory[i].attribute = atoi(sql_row[6]);
- for (j=0; j<MAX_SLOTS; j++)
- p->inventory[i].card[j] = atoi(sql_row[7+j]);
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " inventory");
- }
-
- //read cart.
- //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
- str_p = tmp_sql;
- str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
-
- for (j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`", j);
-
- str_p += sprintf(str_p, " FROM `%s` WHERE `char_id`='%d'", cart_db, char_id);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
- p->cart[i].id = atoi(sql_row[0]);
- p->cart[i].nameid = atoi(sql_row[1]);
- p->cart[i].amount = atoi(sql_row[2]);
- p->cart[i].equip = atoi(sql_row[3]);
- p->cart[i].identify = atoi(sql_row[4]);
- p->cart[i].refine = atoi(sql_row[5]);
- p->cart[i].attribute = atoi(sql_row[6]);
- for(j=0; j<MAX_SLOTS; j++)
- p->cart[i].card[j] = atoi(sql_row[7+j]);
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " cart");
- }
-
- //read skill
- //`skill` (`char_id`, `id`, `lv`)
- sprintf(tmp_sql, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`='%d'",skill_db, char_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
- n = atoi(sql_row[0]);
- p->skill[n].id = n; //memory!? shit!.
- p->skill[n].lv = atoi(sql_row[1]);
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " skills");
- }
-/* Global-reg loading is now handled by the inter-server.
- //global_reg
- //`global_reg_value` (`char_id`, `str`, `value`)
- sprintf(tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- i = 0;
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
- strcpy (p->global_reg[i].str, sql_row[0]);
- strcpy (p->global_reg[i].value, sql_row[1]);
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " reg_values");
- }
- p->global_reg_num=i;
-*/
- //Shamelessly stolen from its_sparky (ie: thanks) and then assimilated by [Skotlex]
- //Friend list
- sprintf(tmp_sql, "SELECT f.friend_account, f.friend_id, c.name FROM `%s` f LEFT JOIN `%s` c ON f.friend_account=c.account_id AND f.friend_id=c.char_id WHERE f.char_id='%d'", friend_db, char_db, char_id);
-
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
- if(sql_res)
- {
- for(i = 0; (sql_row = mysql_fetch_row(sql_res)) && i<MAX_FRIENDS; i++)
- {
- if(sql_row) { //need to check if we have sql_row before we check if we have sql_row[2] because we don't want a segfault
- if(sql_row[2]) {
- p->friends[i].account_id = atoi(sql_row[0]);
- p->friends[i].char_id = atoi(sql_row[1]);
- strncpy(p->friends[i].name, sql_row[2], NAME_LENGTH-1); //The -1 is to avoid losing the ending \0 [Skotlex]
- }
- }
- }
- mysql_free_result(sql_res);
- strcat (t_msg, " friends");
- }
-
- if (save_log)
- ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
-
- cp = idb_ensure(char_db_, char_id, create_charstatus);
- memcpy(cp, p, sizeof(struct mmo_charstatus));
- return 1;
-}
-
-// For quick selection of data when displaying the char menu. [Skotlex]
-//
-int mmo_char_fromsql_short(int char_id, struct mmo_charstatus *p){
- char t_msg[128];
- double exp;
- memset(p, 0, sizeof(struct mmo_charstatus));
- t_msg[0]= '\0';
-
- p->char_id = char_id;
-// ShowInfo("Quick Char load request (%d)\n", char_id);
- //`char`( `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, //9
- //`str`,`agi`,`vit`,`int`,`dex`,`luk`, //15
- //`max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, //21
- //`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`, //27
- //`hair`,`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, //35
- //`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`)
- //splite 2 parts. cause veeeery long SQL syntax
-
- sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
- "`str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res) {
- sql_row = mysql_fetch_row(sql_res);
- if (!sql_row)
- { //Just how does this happens? [Skotlex]
- ShowError("Requested non-existant character id: %d!\n", char_id);
- mysql_free_result(sql_res);
- return 0;
- }
- p->char_id = char_id;
- p->account_id = atoi(sql_row[1]);
- p->char_num = atoi(sql_row[2]);
- strcpy(p->name, sql_row[3]);
- p->class_ = atoi(sql_row[4]);
- p->base_level = atoi(sql_row[5]);
- p->job_level = atoi(sql_row[6]);
- exp = atof(sql_row[7]);
- p->base_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
- exp = atof(sql_row[8]);
- p->job_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
- p->zeny = atoi(sql_row[9]);
- p->str = atoi(sql_row[10]);
- p->agi = atoi(sql_row[11]);
- p->vit = atoi(sql_row[12]);
- p->int_ = atoi(sql_row[13]);
- p->dex = atoi(sql_row[14]);
- p->luk = atoi(sql_row[15]);
- p->max_hp = atoi(sql_row[16]);
- p->hp = atoi(sql_row[17]);
- p->max_sp = atoi(sql_row[18]);
- p->sp = atoi(sql_row[19]);
- p->status_point = atoi(sql_row[20]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[20]);
- p->skill_point = atoi(sql_row[21]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[21]);
- //free mysql result.
- mysql_free_result(sql_res);
- strcat (t_msg, " status");
- } else
- ShowError("Load char failed (%d - table %s).\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
-
- sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`hair`,`hair_color`,"
- "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`"
- "FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
- sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
- if (sql_row) {
-
- p->option = atoi(sql_row[0]); p->karma = atoi(sql_row[1]); p->manner = atoi(sql_row[2]);
- p->hair = atoi(sql_row[3]); p->hair_color = atoi(sql_row[4]); p->clothes_color = atoi(sql_row[5]);
- p->weapon = atoi(sql_row[6]); p->shield = atoi(sql_row[7]);
- p->head_top = atoi(sql_row[8]); p->head_mid = atoi(sql_row[9]); p->head_bottom = atoi(sql_row[10]);
-
- strcat (t_msg, " status2");
- } else
- ShowError("Char load failed (%d - table %s)\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
- //free mysql result.
- if (sql_res)
- mysql_free_result(sql_res);
-// if (save_log) //Too much spam :/
-// ShowInfo("Quick Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
-
- return 1;
-}
-//==========================================================================================================
-int mmo_char_sql_init(void) {
- ShowInfo("Begin Initializing.......\n");
- char_db_= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA, sizeof(int));
- // memory initialize
- memset(&char_dat, 0, sizeof(struct mmo_charstatus));
- if(char_per_account == 0){
- ShowStatus("Chars per Account: 'Unlimited'.......\n");
- }else{
- ShowStatus("Chars per Account: '%d'.......\n", char_per_account);
- }
-
- //the 'set offline' part is now in check_login_conn ...
- //if the server connects to loginserver
- //it will dc all off players
- //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)
- set_all_offline_sql();
-
- ShowInfo("Finished initilizing.......\n");
-
- return 0;
-}
-
-//==========================================================================================================
-
-int make_new_char_sql(int fd, unsigned char *dat) {
- struct char_session_data *sd;
- char name[NAME_LENGTH];
- char t_name[NAME_LENGTH*2];
- unsigned int i; // Used in for loop and comparing with strlen, safe to be unsigned. [Lance]
- int char_id, temp;
-
- strncpy(name, dat, NAME_LENGTH);
- name[NAME_LENGTH-1] = '\0'; //Always terminate string.
- trim(name,TRIM_CHARS); //Trim character name. [Skotlex]
- jstrescapecpy(t_name, name);
-
- // disabled until fixed >.>
- // Note: escape characters should be added to jstrescape()!
- //mysql_real_escape_string(&mysql_handle, t_name, t_name_temp, sizeof(t_name_temp));
-
- if (!session_isValid(fd) || !(sd = (struct char_session_data*)session[fd]->session_data))
- return -2;
-
- ShowInfo("New character request (%d)\n", sd->account_id);
-
- //check name != main chat nick [LuzZza]
- if(strcmpi(name, main_chat_nick) == 0) {
- ShowInfo("Create char failed (%d): this nick (%s) reserved for mainchat messages.\n", sd->account_id, name);
- return -2;
- }
-
- //check for charcount (maxchars) :)
- if(char_per_account != 0){
- sprintf(tmp_sql, "SELECT `account_id` FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if(sql_res){
- //ok
- temp = (int)mysql_num_rows(sql_res);
- if(temp >= char_per_account){
- //hehe .. limit exceeded :P
- ShowInfo("Create char failed (%d): charlimit exceeded.\n", sd->account_id);
- mysql_free_result(sql_res);
- return -2;
- }
- mysql_free_result(sql_res);
- }
- }
-
- // Check Authorised letters/symbols in the name of the character
- if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
- for (i = 0; i < NAME_LENGTH && name[i]; i++)
- if (strchr(char_name_letters, name[i]) == NULL)
- return -2;
- } else if (char_name_option == 2) { // 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;
- } // else, all letters/symbols are authorised (except control char removed before)
-
- //check stat error
- if ((dat[24]+dat[25]+dat[26]+dat[27]+dat[28]+dat[29]!=6*5 ) || // stats
- (dat[30] >= 9) || // slots (dat[30] can not be negativ)
- (dat[33] <= 0) || (dat[33] >= 24) || // hair style
- (dat[31] >= 9)) { // hair color (dat[31] can not be negativ)
- if (log_char) {
- // char.log to charlog
- sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
- //query
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
- return -2;
- } // for now we have checked: stat points used <31, char slot is less then 9, hair style/color values are acceptable
-
- // check individual stat value
- for(i = 24; i <= 29; i++) {
- if (dat[i] < 1 || dat[i] > 9) {
- if (log_char) {
- // char.log to charlog
- sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
- //query
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
- return -2;
- }
- } // now we know that every stat has proper value but we have to check if str/int agi/luk vit/dex pairs are correct
-
- if( ((dat[24]+dat[27]) > 10) || ((dat[25]+dat[29]) > 10) || ((dat[26]+dat[28]) > 10) ) {
- if (log_char) {
- // char.log to charlog
- sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
- //query
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
- return -2;
- } // now when we have passed all stat checks
-
- if (log_char) {
- // char.log to charlog
- sprintf(tmp_sql,"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, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
- //query
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- //printf("make new char %d-%d %s %d, %d, %d, %d, %d, %d - %d, %d" RETCODE,
- // fd, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
-
- //Check Name (already in use?)
- sprintf(tmp_sql, "SELECT 1 FROM `%s` WHERE `name` = '%s'",char_db, t_name);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return -2;
- }
- sql_res = mysql_store_result(&mysql_handle);
- if(sql_res){
- temp = (int)mysql_num_rows(sql_res);
- mysql_free_result(sql_res);
- if (temp > 0) {
- ShowInfo("Create char failed: charname already in use\n");
- return -1;
- }
- }
-
- // check char slot.
- sprintf(tmp_sql, "SELECT `account_id`, `char_num` FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d'",char_db, sd->account_id, dat[30]);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
-
- if(sql_res){
- temp = (int)mysql_num_rows(sql_res);
- mysql_free_result(sql_res);
- if (temp > 0) {
- ShowWarning("Create char failed (%d, slot: %d), slot already in use\n", sd->account_id, dat[30]);
- return -2;
- }
- }
-
- //New Querys [Sirius]
- //Insert the char to the 'chardb' ^^
- sprintf(tmp_sql, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
- "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
- "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
- char_db, sd->account_id , dat[30] , t_name, start_zeny, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29],
- (40 * (100 + dat[26])/100) , (40 * (100 + dat[26])/100 ), (11 * (100 + dat[27])/100), (11 * (100 + dat[27])/100), dat[33], dat[31],
- mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return -2; //No, stop the procedure!
- }
- //Now we need the charid from sql!
- if(mysql_field_count(&mysql_handle) == 0 &&
- mysql_insert_id(&mysql_handle) > 0)
- char_id = (int)mysql_insert_id(&mysql_handle);
- else {
- //delete the char ..(no trash in DB!) but how is this possible?
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' AND `name` = '%s'", char_db, sd->account_id, dat[30], t_name);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return -2; //XD end of the (World? :P) .. charcreate (denied)
- }
- //Give the char the default items
- //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
- if (start_weapon > 0) { //add Start Weapon (Knife?)
- sprintf(tmp_sql,"INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon,1,0x02,1);
- if (mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- if (start_armor > 0) { //Add default armor (cotton shirt?)
- sprintf(tmp_sql,"INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor,1,0x10,1);
- if (mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, dat[30], name);
- return char_id;
-}
-
-/*----------------------------------------------------------------------------------------------------------*/
-/* Delete char - davidsiaw */
-/*----------------------------------------------------------------------------------------------------------*/
-/* Returns 0 if successful
- * Returns < 0 for error
- */
-int delete_char_sql(int char_id, int partner_id)
-{
- char char_name[NAME_LENGTH], t_name[NAME_LENGTH*2]; //Name needs be escaped.
- int account_id=0, party_id=0, guild_id=0, char_base_level=0;
-
- sprintf(tmp_sql, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level` FROM `%s` WHERE `char_id`='%d'",char_db, char_id);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
-
- if(sql_res)
- sql_row = mysql_fetch_row(sql_res);
-
- if (sql_res == NULL || sql_row == NULL)
- {
- ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n");
- if (sql_res)
- mysql_free_result(sql_res);
- return -1;
- }
- strncpy(char_name, sql_row[0], NAME_LENGTH);
- char_name[NAME_LENGTH-1] = '\0';
- jstrescapecpy(t_name, char_name); //Escape string for sql use... [Skotlex]
- account_id = atoi(sql_row[1]);
- party_id = atoi(sql_row[2]);
- guild_id = atoi(sql_row[3]);
- char_base_level = atoi(sql_row[4]);
- mysql_free_result(sql_res); //Let's free this as soon as possible to avoid problems later on.
-
- //check for config char del condition [Lupus]
- if( ( char_del_level > 0 && char_base_level >= char_del_level )
- || ( char_del_level < 0 && char_base_level <= -char_del_level )
- ) {
- ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n",char_name,char_base_level);
- return -1;
- }
-
- /* Divorce [Wizputer] */
- if (partner_id) {
- sprintf(tmp_sql,"UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d'",char_db,partner_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND `char_id`='%d'",inventory_db,WEDDING_RING_M,WEDDING_RING_F,partner_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- //Make the character leave the party [Skotlex]
- if (party_id)
- inter_party_leave(party_id, account_id, char_id);
-
- /* delete char's pet */
- //Delete the hatched pet if you have one...
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'",pet_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- // Komurka's suggested way to clear pets, modified by [Skotlex] (because I always personalize what I do :X)
- //Removing pets that are in the char's inventory....
- { //NOTE: The syntax for multi-table deletes is a bit changed between 4.0 and 4.1 regarding aliases, so we have to consider the version... [Skotlex]
- //Since we only care about the major and minor version, a double conversion is good enough. (4.1.20 -> 4.10000)
- double mysql_version = atof(mysql_get_server_info(&mysql_handle));
-
- sprintf(tmp_sql,
- "delete FROM `%s` USING `%s` as c LEFT JOIN `%s` as i ON c.char_id = i.char_id, `%s` as p WHERE c.char_id = '%d' AND i.card0 = -256 AND p.pet_id = (i.card1|(i.card2<<2))",
- (mysql_version<4.1?pet_db:"p"), char_db, inventory_db, pet_db, char_id);
-
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- //Removing pets that are in the char's cart....
- sprintf(tmp_sql,
- "delete FROM `%s` USING `%s` as c LEFT JOIN `%s` as i ON c.char_id = i.char_id, `%s` as p WHERE c.char_id = '%d' AND i.card0 = -256 AND p.pet_id = (i.card1|(i.card2<<2))",
- (mysql_version<4.1?pet_db:"p"), char_db, cart_db, pet_db, char_id);
-
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- /* delete char's friends list */
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id` = '%d'",friend_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete char from other's friend list */
- //NOTE: Won't this cause problems for people who are already online? [Skotlex]
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `friend_id` = '%d'",friend_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete inventory */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",inventory_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete cart inventory */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",cart_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete memo areas */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",memo_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete character registry */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* delete skills */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",skill_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
-#ifdef ENABLE_SC_SAVING
- /* status changes */
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
- scdata_db, account_id, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-#endif
-
- if (log_char) {
- sprintf(tmp_sql,"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, t_name);
- //query
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- /* delete character */
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",char_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- /* No need as we used inter_guild_leave [Skotlex]
- // Also delete info from guildtables.
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",guild_member_db, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- */
-
- sprintf(tmp_sql, "SELECT `guild_id` FROM `%s` WHERE `master` = '%s'", guild_db, t_name);
-
- if (mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- } else {
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res == NULL) {
- if (mysql_errno(&mysql_handle) != 0)
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return -1;
- } else {
- int rows = (int)mysql_num_rows(sql_res);
- mysql_free_result(sql_res);
- if (rows > 0) {
- mapif_parse_BreakGuild(0,guild_id);
- }
- else if (guild_id) //Leave your guild.
- inter_guild_leave(guild_id, account_id, char_id);
- }
- }
- return 0;
-}
-
-//==========================================================================================================
-
-int count_users(void) {
- int i, users;
-
- if (login_fd > 0 && session[login_fd]){
- users = 0;
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if (server_fd[i] > 0) {
- users += server[i].users;
- }
- }
- return users;
- }
- return 0;
-}
-
-int mmo_char_send006b(int fd, struct char_session_data *sd) {
- int i, j, found_num = 0;
- struct mmo_charstatus *p = NULL;
- const int offset = 24;
- WFIFOHEAD(fd, offset +9*106);
-
- set_char_online(-1, 99,sd->account_id);
-
- //search char.
- sprintf(tmp_sql, "SELECT `char_id` FROM `%s` WHERE `account_id` = '%d'",char_db, sd->account_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- found_num = (int)mysql_num_rows(sql_res);
-// ShowInfo("number of chars: %d\n", found_num);
- i = 0;
- while((sql_row = mysql_fetch_row(sql_res))) {
- sd->found_char[i] = atoi(sql_row[0]);
- i++;
- }
- mysql_free_result(sql_res);
- }
-
- for(i = found_num; i < 9; i++)
- sd->found_char[i] = -1;
-
- memset(WFIFOP(fd, 0), 0, offset + found_num * 106);
- WFIFOW(fd, 0) = 0x6b;
- WFIFOW(fd, 2) = offset + found_num * 106;
-
- if (save_log)
- ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
-
- for(i = 0; i < found_num; i++) {
- mmo_char_fromsql_short(sd->found_char[i], &char_dat);
-
- p = &char_dat;
-
- j = offset + (i * 106); // increase speed of code
-
- WFIFOL(fd,j) = p->char_id;
- WFIFOL(fd,j+4) = p->base_exp>LONG_MAX?LONG_MAX:p->base_exp;
- WFIFOL(fd,j+8) = p->zeny;
- WFIFOL(fd,j+12) = p->job_exp>LONG_MAX?LONG_MAX:p->job_exp;
- WFIFOL(fd,j+16) = p->job_level;
-
- WFIFOL(fd,j+20) = 0;
- WFIFOL(fd,j+24) = 0;
- WFIFOL(fd,j+28) = p->option;
-
- WFIFOL(fd,j+32) = p->karma;
- WFIFOL(fd,j+36) = p->manner;
-
- WFIFOW(fd,j+40) = (p->status_point > SHRT_MAX) ? SHRT_MAX : p->status_point;
- WFIFOW(fd,j+42) = (p->hp > SHRT_MAX) ? SHRT_MAX : p->hp;
- WFIFOW(fd,j+44) = (p->max_hp > SHRT_MAX) ? SHRT_MAX : p->max_hp;
- WFIFOW(fd,j+46) = (p->sp > SHRT_MAX) ? SHRT_MAX : p->sp;
- WFIFOW(fd,j+48) = (p->max_sp > SHRT_MAX) ? SHRT_MAX : p->max_sp;
- WFIFOW(fd,j+50) = DEFAULT_WALK_SPEED; // p->speed;
- WFIFOW(fd,j+52) = p->class_;
- WFIFOW(fd,j+54) = p->hair;
- WFIFOW(fd,j+56) = p->option&0x20?0:p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
- WFIFOW(fd,j+58) = p->base_level;
- WFIFOW(fd,j+60) = (p->skill_point > SHRT_MAX) ? SHRT_MAX : p->skill_point;
- WFIFOW(fd,j+62) = p->head_bottom;
- WFIFOW(fd,j+64) = p->shield;
- WFIFOW(fd,j+66) = p->head_top;
- WFIFOW(fd,j+68) = p->head_mid;
- WFIFOW(fd,j+70) = p->hair_color;
- WFIFOW(fd,j+72) = p->clothes_color;
-
- memcpy(WFIFOP(fd,j+74), p->name, NAME_LENGTH);
-
- WFIFOB(fd,j+98) = (p->str > UCHAR_MAX) ? UCHAR_MAX : p->str;
- WFIFOB(fd,j+99) = (p->agi > UCHAR_MAX) ? UCHAR_MAX : p->agi;
- WFIFOB(fd,j+100) = (p->vit > UCHAR_MAX) ? UCHAR_MAX : p->vit;
- WFIFOB(fd,j+101) = (p->int_ > UCHAR_MAX) ? UCHAR_MAX : p->int_;
- WFIFOB(fd,j+102) = (p->dex > UCHAR_MAX) ? UCHAR_MAX : p->dex;
- WFIFOB(fd,j+103) = (p->luk > UCHAR_MAX) ? UCHAR_MAX : p->luk;
- WFIFOB(fd,j+104) = p->char_num;
- }
-
- WFIFOSET(fd,WFIFOW(fd,2));
-// printf("mmo_char_send006b end..\n");
- return 0;
-}
-
-int send_accounts_tologin(int tid, unsigned int tick, int id, int data);
-
-int parse_tologin(int fd) {
- int i;
- struct char_session_data *sd;
- RFIFOHEAD(fd);
- // only login-server can have an access to here.
- // so, if it isn't the login-server, we disconnect the session.
- //session eof check!
- if(fd != login_fd)
- session[fd]->eof = 1;
- if(session[fd]->eof) {
- if (fd == login_fd) {
- ShowWarning("Connection to login-server lost (connection #%d).\n", fd);
- login_fd = -1;
- }
- do_close(fd);
- return 0;
- }
-
- sd = (struct char_session_data*)session[fd]->session_data;
-
- // hehe. no need to set user limit on SQL version. :P
- // but char limitation is good way to maintain server. :D
- while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
-// printf("parse_tologin : %d %d %x\n", fd, RFIFOREST(fd), RFIFOW(fd, 0));
-
- switch(RFIFOW(fd, 0)){
- case 0x2711:
- if (RFIFOREST(fd) < 3)
- return 0;
- if (RFIFOB(fd, 2)) {
- //printf("connect login server error : %d\n", RFIFOB(fd, 2));
- ShowError("Can not connect to login-server.\n");
- ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
- ShowError("Also, please make sure your login db has the correct coounication username/passwords and the gender of the account is S.\n");
- ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
- return 0;
- //exit(1); //fixed for server shutdown.
- }else {
- ShowStatus("Connected to login-server (connection #%d).\n", fd);
-
- //Send online accounts to login server.
- send_accounts_tologin(-1, gettick(), 0, 0);
-
- // if no map-server already connected, display a message...
- for(i = 0; i < MAX_MAP_SERVERS; i++)
- if (server_fd[i] > 0 && server[i].map[0]) // if map-server online and at least 1 map
- break;
- if (i == MAX_MAP_SERVERS)
- ShowStatus("Awaiting maps from map-server.\n");
- }
- RFIFOSKIP(fd, 3);
- break;
-
- case 0x2713:
- if(RFIFOREST(fd)<51)
- return 0;
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2)) {
- WFIFOHEAD(i,3);
- if (RFIFOB(fd,6) != 0) {
- WFIFOW(i,0) = 0x6c;
- WFIFOB(i,2) = 0x42;
- WFIFOSET(i,3);
- } else if (max_connect_user == 0 || count_users() < max_connect_user) {
-// if (max_connect_user == 0)
-// printf("max_connect_user (unlimited) -> accepted.\n");
-// else
-// printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user);
- sd->connect_until_time = (time_t)RFIFOL(fd,47);
- memcpy(sd->email, RFIFOP(fd, 7), 40);
- // send characters to player
- mmo_char_send006b(i, sd);
- } else if(isGM(sd->account_id) >= gm_allow_level) {
- sd->connect_until_time = (time_t)RFIFOL(fd,47);
- memcpy(sd->email, RFIFOP(fd, 7), 40);
- // send characters to player
- mmo_char_send006b(i, sd);
- } else {
- // refuse connection: too much online players
-// printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user);
- WFIFOW(i,0) = 0x6c;
- WFIFOW(i,2) = 0;
- WFIFOSET(i,3);
- }
- }
- }
- RFIFOSKIP(fd,51);
- break;
-
- case 0x2717:
- if (RFIFOREST(fd) < 50)
- return 0;
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
- if (sd->account_id == RFIFOL(fd,2)) {
- memcpy(sd->email, RFIFOP(fd, 6), 40);
- sd->connect_until_time = (time_t)RFIFOL(fd,46);
- break;
- }
- }
- }
- RFIFOSKIP(fd,50);
- break;
-
- // login-server alive packet
- case 0x2718:
- if (RFIFOREST(fd) < 2)
- return 0;
- RFIFOSKIP(fd,2);
- break;
-
- // Receiving authentification from Freya-type login server (to avoid char->login->char)
- case 0x2719:
- if (RFIFOREST(fd) < 18)
- return 0;
- // to conserv a maximum of authentification, search if account is already authentified and replace it
- // that will reduce multiple connection too
- for(i = 0; i < AUTH_FIFO_SIZE; i++)
- if (auth_fifo[i].account_id == RFIFOL(fd,2))
- break;
- // if not found, use next value
- if (i == AUTH_FIFO_SIZE) {
- if (auth_fifo_pos >= AUTH_FIFO_SIZE)
- auth_fifo_pos = 0;
- i = auth_fifo_pos;
- auth_fifo_pos++;
- }
- //printf("auth_fifo set (auth #%d) - account: %d, secure: %08x-%08x\n", i, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10));
- auth_fifo[i].account_id = RFIFOL(fd,2);
- auth_fifo[i].char_id = 0;
- auth_fifo[i].login_id1 = RFIFOL(fd,6);
- auth_fifo[i].login_id2 = RFIFOL(fd,10);
- auth_fifo[i].delflag = 2; // 0: auth_fifo canceled/void, 2: auth_fifo received from login/map server in memory, 1: connection authentified
- auth_fifo[i].char_pos = 0;
- auth_fifo[i].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
- auth_fifo[i].ip = RFIFOL(fd,14);
- //auth_fifo[i].map_auth = 0;
- RFIFOSKIP(fd,18);
- break;
-
- case 0x2721: // gm reply. I don't want to support this function.
- if (RFIFOREST(fd) < 10)
- return 0;
- RFIFOSKIP(fd, 10);
-/* Note that this is the code from char-txt! Even uncommenting it will not work.
- printf("0x2721:GM reply\n");
- {
- int oldacc, newacc;
- unsigned char buf[64];
- if (RFIFOREST(fd) < 10)
- return 0;
- oldacc = RFIFOL(fd, 2);
- newacc = RFIFOL(fd, 6);
- RFIFOSKIP(fd, 10);
- if (newacc > 0) {
- for(i=0;i<char_num;i++){
- if(char_dat[i].account_id==oldacc)
- char_dat[i].account_id=newacc;
- }
- }
- WBUFW(buf,0)=0x2b0b;
- WBUFL(buf,2)=oldacc;
- WBUFL(buf,6)=newacc;
- mapif_sendall(buf,10);
-// printf("char -> map\n");
- }
-*/
- break;
- case 0x2723: // changesex reply (modified by [Yor])
- if (RFIFOREST(fd) < 7)
- return 0;
- {
- int acc, sex;
- unsigned char buf[16];
- MYSQL_RES* sql_res2;
- acc = RFIFOL(fd,2);
- sex = RFIFOB(fd,6);
- RFIFOSKIP(fd, 7);
- if (acc > 0) {
- sprintf(tmp_sql, "SELECT `char_id`,`class`,`skill_point`,`guild_id` FROM `%s` WHERE `account_id` = '%d'",char_db, acc);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res2 = mysql_store_result(&mysql_handle);
-
- while(sql_res2 && (sql_row = mysql_fetch_row(sql_res2))) {
- int char_id, guild_id, jobclass, skill_point, class_;
- char_id = atoi(sql_row[0]);
- jobclass = atoi(sql_row[1]);
- skill_point = atoi(sql_row[2]);
- guild_id = atoi(sql_row[3]);
- class_ = jobclass;
- if (jobclass == JOB_BARD || jobclass == JOB_DANCER ||
- jobclass == JOB_CLOWN || jobclass == JOB_GYPSY ||
- jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
- // job modification
- if (jobclass == JOB_BARD || jobclass == JOB_DANCER) {
- class_ = (sex) ? JOB_BARD : JOB_DANCER;
- } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) {
- class_ = (sex) ? JOB_CLOWN : JOB_GYPSY;
- } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
- class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER;
- }
- // remove specifical skills of classes 19,20 4020,4021 and 4042,4043
- sprintf(tmp_sql, "SELECT `lv` FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'",skill_db, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- while(( sql_row = mysql_fetch_row(sql_res))) {
- skill_point += atoi(sql_row[0]);
- }
- mysql_free_result(sql_res);
- }
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'",skill_db, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- // to avoid any problem with equipment and invalid sex, equipment is unequiped.
- sprintf(tmp_sql, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'",inventory_db, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql, "UPDATE `%s` SET `class`='%d' , `skill_point`='%d' , `weapon`='0' , `shield`='0' , `head_top`='0' , `head_mid`='0' , `head_bottom`='0' WHERE `char_id` = '%d'",char_db, class_, skill_point, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- if (guild_id) //If there is a guild, update the guild_member data [Skotlex]
- inter_guild_sex_changed(guild_id, acc, char_id, sex);
- }
- if (sql_res2)
- mysql_free_result(sql_res2);
- }
- // disconnect player if online on char-server
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
- if (sd->account_id == acc) {
- session[i]->eof = 1;
- break;
- }
- }
- }
-
- WBUFW(buf,0) = 0x2b0d;
- WBUFL(buf,2) = acc;
- WBUFB(buf,6) = sex;
-
- mapif_sendall(buf, 7);
- }
- break;
-
- // account_reg2•ΟX’Κ’m
- case 0x2729:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- { //Receive account_reg2 registry, forward to map servers.
- unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16];
- memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
-// WBUFW(buf,0) = 0x2b11;
- 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));
- RFIFOSKIP(fd, RFIFOW(fd,2));
- }
- break;
-
- // State change of account/ban notification (from login-server) by [Yor]
- case 0x2731:
- if (RFIFOREST(fd) < 11)
- return 0;
- // send to all map-servers to disconnect the player
- {
- unsigned char buf[16];
- WBUFW(buf,0) = 0x2b14;
- WBUFL(buf,2) = RFIFOL(fd,2);
- WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
- WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
- mapif_sendall(buf, 11);
- }
- // disconnect player if online on char-server
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
- if (sd->account_id == RFIFOL(fd,2)) {
- session[i]->eof = 1;
- break;
- }
- }
- }
- RFIFOSKIP(fd,11);
- break;
-
- case 0x2732:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- if(!char_gm_read) {
- unsigned char buf[32000];
- if (gm_account != NULL)
- aFree(gm_account);
- gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * ((RFIFOW(fd,2) - 4) / 5), 1);
- GM_num = 0;
- for (i = 4; i < RFIFOW(fd,2); i = i + 5) {
- gm_account[GM_num].account_id = RFIFOL(fd,i);
- gm_account[GM_num].level = (int)RFIFOB(fd,i+4);
- //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
- GM_num++;
- }
- ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num);
- // send new gm acccounts level to map-servers
- memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
- WBUFW(buf,0) = 0x2b15;
- mapif_sendall(buf, RFIFOW(fd,2));
- }
- RFIFOSKIP(fd,RFIFOW(fd,2));
- break;
-
- // Receive GM accounts [Freya login server packet by Yor]
- case 0x2733:
- // add test here to remember that the login-server is Freya-type
- // sprintf (login_server_type, "Freya");
- if (RFIFOREST(fd) < 7)
- return 0;
- {
- int new_level = 0;
- for(i = 0; i < GM_num; i++)
- if (gm_account[i].account_id == RFIFOL(fd,2)) {
- if (gm_account[i].level != (int)RFIFOB(fd,6)) {
- gm_account[i].level = (int)RFIFOB(fd,6);
- new_level = 1;
- }
- break;
- }
- // if not found, add it
- if (i == GM_num) {
- // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???)
- // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows)
- if (((int)RFIFOB(fd,6)) > 0 && GM_num < 4000) {
- if (GM_num == 0) {
- gm_account = (struct gm_account*)aMalloc(sizeof(struct gm_account));
- } else {
- gm_account = (struct gm_account*)aRealloc(gm_account, sizeof(struct gm_account) * (GM_num + 1));
- }
- gm_account[GM_num].account_id = RFIFOL(fd,2);
- gm_account[GM_num].level = (int)RFIFOB(fd,6);
- new_level = 1;
- GM_num++;
- if (GM_num >= 4000)
- ShowWarning("4000 GM accounts found. Next GM accounts are not readed.\n");
- }
- }
- if (new_level == 1) {
- ShowStatus("From login-server: receiving GM account information (%d: level %d).\n", RFIFOL(fd,2), (int)RFIFOB(fd,6));
- mapif_send_gmaccounts();
-
- //create_online_files(); // not change online file for only 1 player (in next timer, that will be done
- // send gm acccounts level to map-servers
- }
- }
- RFIFOSKIP(fd,7);
- break;
-
- //Login server request to kick a character out. [Skotlex]
- case 0x2734:
- if (RFIFOREST(fd) < 6)
- return 0;
- {
- struct online_char_data* character;
- int aid = RFIFOL(fd,2);
- if ((character = idb_get(online_char_db, aid)) != NULL)
- { //Kick out this player.
- if (character->server > -1)
- { //Kick it from the map server it is on.
- mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
- if (!character->waiting_disconnect)
- add_timer(gettick()+15000, chardb_waiting_disconnect, character->account_id, 0);
- character->waiting_disconnect = 1;
- } else { //Manual kick from char server.
- struct char_session_data *tsd;
- int i;
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid)
- {
- WFIFOHEAD(i,3);
- WFIFOW(i,0) = 0x81;
- WFIFOB(i,2) = 2;
- WFIFOSET(i,3);
- break;
- }
- }
- if (i == fd_max) //Shouldn't happen, but just in case.
- set_char_offline(99, aid);
- }
- }
- RFIFOSKIP(fd,6);
- }
- break;
-
- case 0x2735:
- {
- unsigned char buf[2];
- in_addr_t new_ip = 0;
- RFIFOSKIP(fd,2);
-
- WBUFW(buf,0) = 0x2b1e;
- mapif_sendall(buf, 2);
-
- new_ip = resolve_hostbyname(login_ip_str, NULL, NULL);
- if (new_ip && new_ip != login_ip) //Update login ip, too.
- login_ip = new_ip;
-
- new_ip = resolve_hostbyname(char_ip_str, NULL, NULL);
- if (new_ip && new_ip != char_ip)
- { //Update ip.
- char_ip = new_ip;
- ShowInfo("Updating IP for [%s].\n",char_ip_str);
- WFIFOHEAD(fd,6);
- WFIFOW(fd,0) = 0x2736;
- WFIFOL(fd,2) = char_ip;
- WFIFOSET(fd,6);
- }
- break;
- }
- default:
- ShowError("Unknown packet 0x%04x from login server, disconnecting.\n", RFIFOW(fd, 0));
- session[fd]->eof = 1;
- return 0;
- }
- }
-
- RFIFOFLUSH(fd);
-
- return 0;
-}
-
-int request_accreg2(int account_id, int char_id) {
- if (login_fd > 0) {
- WFIFOHEAD(login_fd, 10);
- WFIFOW(login_fd, 0) = 0x272e;
- WFIFOL(login_fd, 2) = account_id;
- WFIFOL(login_fd, 6) = char_id;
- WFIFOSET(login_fd, 10);
- return 1;
- }
- 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;
- }
- return 0;
-}
-
-void char_read_fame_list(void)
-{
- int i;
- struct fame_list fame_item;
-
- // Empty ranking lists
- memset(smith_fame_list, 0, sizeof(smith_fame_list));
- memset(chemist_fame_list, 0, sizeof(chemist_fame_list));
- memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list));
- // Build Blacksmith ranking list
- sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, fame_list_size_smith);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- i = 0;
- while((sql_row = mysql_fetch_row(sql_res))) {
- fame_item.id = atoi(sql_row[0]);
- fame_item.fame = atoi(sql_row[1]);
- strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
- memcpy(&smith_fame_list[i], &fame_item, sizeof(struct fame_list));
-
- if (++i == fame_list_size_smith)
- break;
- }
- mysql_free_result(sql_res);
- }
- // Build Alchemist ranking list
- sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, fame_list_size_chemist);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- i = 0;
- while((sql_row = mysql_fetch_row(sql_res))) {
- fame_item.id = atoi(sql_row[0]);
- fame_item.fame = atoi(sql_row[1]);
- strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
-
- memcpy(&chemist_fame_list[i], &fame_item, sizeof(struct fame_list));
-
- if (++i == fame_list_size_chemist)
- break;
- }
- mysql_free_result(sql_res);
- }
- // Build Taekwon ranking list
- sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- i = 0;
- while((sql_row = mysql_fetch_row(sql_res))) {
- fame_item.id = atoi(sql_row[0]);
- fame_item.fame = atoi(sql_row[1]);
- strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
-
- memcpy(&taekwon_fame_list[i], &fame_item, sizeof(struct fame_list));
-
- if (++i == fame_list_size_taekwon)
- break;
- }
- mysql_free_result(sql_res);
- }
-}
-
-// Send map-servers the fame ranking lists
-int char_send_fame_list(int fd) {
- int i, len = 8;
- unsigned char buf[32000];
-
- WBUFW(buf,0) = 0x2b1b;
-
- for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) {
- memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list));
- len += sizeof(struct fame_list);
- }
- // add blacksmith's block length
- WBUFW(buf, 6) = len;
-
- for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) {
- memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list));
- len += sizeof(struct fame_list);
- }
- // add alchemist's block length
- WBUFW(buf, 4) = len;
-
- for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) {
- memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list));
- len += sizeof(struct fame_list);
- }
- // add total packet length
- WBUFW(buf, 2) = len;
-
- if (fd != -1)
- mapif_send(fd, buf, len);
- else
- mapif_sendall(buf, len);
- return 0;
-}
-
-int search_mapserver(unsigned short map, long ip, short port);
-
-//Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size)
-//Returns 1 on found, 0 on not found (buffer is filled with Unknown char name)
-int char_loadName(int char_id, char* name)
-{
- sprintf(tmp_sql, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
- sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
-
- if (sql_row)
- memcpy(name, sql_row[0], NAME_LENGTH);
- else
- memcpy(name, unknown_char_name, NAME_LENGTH);
- if (sql_res) mysql_free_result(sql_res);
- return sql_row?1:0;
-}
-
-
-int parse_frommap(int fd) {
- int i = 0, j = 0;
- int id;
- RFIFOHEAD(fd);
-
- // Sometimes fd=0, and it will cause server crash. Don't know why. :(
- if (fd <= 0) {
- ShowError("parse_frommap error fd=%d\n", fd);
- return 0;
- }
-
- for(id = 0; id < MAX_MAP_SERVERS; id++)
- if (server_fd[id] == fd)
- break;
- if(id == MAX_MAP_SERVERS)
- session[fd]->eof = 1;
- if(session[fd]->eof) {
- if (id < MAX_MAP_SERVERS) {
- unsigned char buf[16384];
- ShowStatus("Map-server %d (session #%d) has disconnected.\n", id, fd);
- //Notify other map servers that this one is gone. [Skotlex]
- WBUFW(buf,0) = 0x2b20;
- WBUFL(buf,4) = server[id].ip;
- WBUFW(buf,8) = server[id].port;
- j = 0;
- for(i = 0; i < MAX_MAP_PER_SERVER; i++)
- if (server[id].map[i])
- WBUFW(buf,10+(j++)*4) = server[id].map[i];
- if (j > 0) {
- WBUFW(buf,2) = j * 4 + 10;
- mapif_sendallwos(fd, buf, WBUFW(buf,2));
- }
- memset(&server[id], 0, sizeof(struct mmo_map_server));
- sprintf(tmp_sql, "DELETE FROM `ragsrvinfo` WHERE `index`='%d'", server_fd[id]);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- server_fd[id] = -1;
- online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
- }
- do_close(fd);
- return 0;
- }
-
- while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
- switch(RFIFOW(fd, 0)) {
-
- // map-server alive packet
- case 0x2718:
- RFIFOSKIP(fd,2);
- break;
-
- case 0x2af7:
- RFIFOSKIP(fd,2);
- if(char_gm_read) //Re-read gm accounts.
- read_gm_account();
- //Send to login request to reload gm accounts.
- else if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 2);
- WFIFOW(login_fd,0) = 0x2709;
- WFIFOSET(login_fd, 2);
- }
- break;
-
- // mapserver -> map names recv.
- case 0x2afa:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- {
- unsigned char *p = (unsigned char *)&server[id].ip;
- unsigned char buf[16384];
- int x;
- WFIFOHEAD(fd,3+NAME_LENGTH);
-
- memset(server[id].map, 0, sizeof(server[id].map));
- j = 0;
- for(i = 4; i < RFIFOW(fd,2); i += 4) {
- server[id].map[j] = RFIFOW(fd,i);
- j++;
- }
-
- ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
- id, j, p[0], p[1], p[2], p[3], server[id].port);
- ShowStatus("Map-server %d loading complete.\n", id);
-
- if (max_account_id != DEFAULT_MAX_ACCOUNT_ID || max_char_id != DEFAULT_MAX_CHAR_ID)
- mapif_send_maxid(max_account_id, max_char_id); //Send the current max ids to the server to keep in sync [Skotlex]
-
- WFIFOW(fd,0) = 0x2afb;
- WFIFOB(fd,2) = 0;
- // name for wisp to player
- memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
- WFIFOSET(fd,3+NAME_LENGTH);
-
- char_send_fame_list(fd); //Send fame list.
-
- if (j == 0)
- ShowWarning("Map-Server %d have NO maps.\n", id);
- else {
- // Transmitting maps information to the other map-servers
- WBUFW(buf,0) = 0x2b04;
- WBUFW(buf,2) = j * 4 + 10;
- WBUFL(buf,4) = server[id].ip;
- WBUFW(buf,8) = server[id].port;
- memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
- mapif_sendallwos(fd, buf, WBUFW(buf,2));
- }
- // Transmitting the maps of the other map-servers to the new map-server
- for(x = 0; x < MAX_MAP_SERVERS; x++) {
- if (server_fd[x] > 0 && x != id) {
- WFIFOHEAD(fd, 10 +4*MAX_MAP_PER_SERVER);
- WFIFOW(fd,0) = 0x2b04;
- WFIFOL(fd,4) = server[x].ip;
- WFIFOW(fd,8) = server[x].port;
- j = 0;
- for(i = 0; i < MAX_MAP_PER_SERVER; i++)
- if (server[x].map[i])
- WFIFOW(fd,10+(j++)*4) = server[x].map[i];
- if (j > 0) {
- WFIFOW(fd,2) = j * 4 + 10;
- WFIFOSET(fd,WFIFOW(fd,2));
- }
- }
- }
- RFIFOSKIP(fd,RFIFOW(fd,2));
- }
- break;
- //Packet command is now used for sc_data request. [Skotlex]
- case 0x2afc:
- if (RFIFOREST(fd) < 10)
- return 0;
- {
- int aid, cid;
- aid = RFIFOL(fd,2);
- cid = RFIFOL(fd,6);
- RFIFOSKIP(fd, 10);
-#ifdef ENABLE_SC_SAVING
- sprintf(tmp_sql, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
- scdata_db, aid, cid);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- break;
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- struct status_change_data data;
- int count = 0;
- WFIFOHEAD(fd, 14+50*sizeof(struct status_change_data));
- WFIFOW(fd, 0) = 0x2b1d;
- WFIFOL(fd, 4) = aid;
- WFIFOL(fd, 8) = cid;
- while((sql_row = mysql_fetch_row(sql_res)) && count < 50)
- {
- data.type = atoi(sql_row[0]);
- data.tick = atoi(sql_row[1]);
- data.val1 = atoi(sql_row[2]);
- data.val2 = atoi(sql_row[3]);
- data.val3 = atoi(sql_row[4]);
- data.val4 = atoi(sql_row[5]);
- memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &data, sizeof(struct status_change_data));
- count++;
- }
- if (count >= 50)
- ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
- mysql_free_result(sql_res);
- if (count > 0)
- {
- WFIFOW(fd, 2) = 14 + count*sizeof(struct status_change_data);
- WFIFOW(fd, 12) = count;
- WFIFOSET(fd, WFIFOW(fd,2));
-
- //Clear the data once loaded.
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
-#endif
- break;
- }
- //set MAP user count
- case 0x2afe:
- if (RFIFOREST(fd) < 4)
- return 0;
- if (RFIFOW(fd,2) != server[id].users) {
- server[id].users = RFIFOW(fd,2);
- ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
- }
- RFIFOSKIP(fd, 4);
- break;
- // set MAP user
- case 0x2aff:
- if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- {
- //TODO: When data mismatches memory, update guild/party online/offline states.
- int i, aid, cid;
- struct online_char_data* character;
-
- online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
- server[id].users = RFIFOW(fd,4);
- for(i = 0; i < server[id].users; i++) {
- aid = RFIFOL(fd,6+i*8);
- cid = RFIFOL(fd,6+i*8+4);
- character = idb_ensure(online_char_db, aid, create_online_char_data);
- if (character->server > -1 && character->server != id)
- {
- ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
- character->account_id, character->char_id, character->server, id, aid, cid);
- mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
- }
- character->server = id;
- character->char_id = cid;
- }
- //If any chars remain in -2, they will be cleaned in the cleanup timer.
- RFIFOSKIP(fd,RFIFOW(fd,2));
- break;
- }
- // char saving
- case 0x2b01:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- {
- 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));
- RFIFOSKIP(fd,size);
- break;
- }
- //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
- if (RFIFOB(fd,12) || (
- (character = idb_get(online_char_db, aid)) != NULL &&
- character->char_id == cid))
- {
- 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);
- set_char_online(id, cid, aid);
- }
-
- if (RFIFOB(fd,12))
- { //Flag? Set character offline after saving [Skotlex]
- set_char_offline(cid, aid);
- WFIFOHEAD(fd, 10);
- WFIFOW(fd, 0) = 0x2b21; //Save ack only needed on final save.
- WFIFOL(fd, 2) = aid;
- WFIFOL(fd, 6) = cid;
- WFIFOSET(fd, 10);
- }
- RFIFOSKIP(fd,size);
- break;
- }
- // req char selection
- case 0x2b02:
- if (RFIFOREST(fd) < 18)
- return 0;
-
- if (auth_fifo_pos >= AUTH_FIFO_SIZE)
- auth_fifo_pos = 0;
-
- auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd, 2);
- auth_fifo[auth_fifo_pos].char_id = 0;
- auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd, 6);
- auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10);
- auth_fifo[auth_fifo_pos].delflag = 2;
- auth_fifo[auth_fifo_pos].char_pos = 0;
- auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
- auth_fifo[auth_fifo_pos].ip = RFIFOL(fd,14);
- auth_fifo_pos++;
- {
- WFIFOHEAD(fd, 7);
- WFIFOW(fd, 0) = 0x2b03;
- WFIFOL(fd, 2) = RFIFOL(fd, 2);
- WFIFOB(fd, 6) = 0;
- WFIFOSET(fd, 7);
- }
- RFIFOSKIP(fd, 18);
- break;
-
- // request "change map server"
- case 0x2b05:
- if (RFIFOREST(fd) < 35)
- return 0;
- {
- unsigned short name;
- int map_id, map_fd = -1;
- struct online_char_data* data;
- struct mmo_charstatus* char_data;
- name = RFIFOW(fd,18);
- map_id = search_mapserver(name, RFIFOL(fd,24), RFIFOW(fd,28)); //Locate mapserver by ip and port.
- if (map_id >= 0)
- map_fd = server_fd[map_id];
- //Char should just had been saved before this packet, so this should be safe. [Skotlex]
- char_data = uidb_get(char_db_,RFIFOL(fd,14));
- if (char_data == NULL)
- { //Really shouldn't happen.
- mmo_char_fromsql(RFIFOL(fd,14), &char_dat);
- char_data = &char_dat;
- }
- //Tell the new map server about this player using Kevin's new auth packet. [Skotlex]
- if (map_fd>=0 && session[map_fd] && char_data)
- { //Send the map server the auth of this player.
- //Update the "last map" as this is where the player must be spawned on the new map server.
- WFIFOHEAD(fd, 30);
- WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
- char_data->last_point.map = RFIFOW(fd,18);
- char_data->last_point.x = RFIFOW(fd,20);
- char_data->last_point.y = RFIFOW(fd,22);
- char_data->sex = RFIFOB(fd,30); // Buuyo^
-
- WFIFOW(map_fd,0) = 0x2afd;
- WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
- WFIFOL(map_fd,4) = RFIFOL(fd, 2); //Account ID
- WFIFOL(map_fd,8) = RFIFOL(fd, 6); //Login1
- WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2
- WFIFOL(map_fd,12) = (unsigned long)0; //TODO: connect_until_time, how do I figure it out right now?
- memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus));
- WFIFOSET(map_fd, WFIFOW(map_fd,2));
- data = idb_ensure(online_char_db, RFIFOL(fd, 2), create_online_char_data);
- data->char_id = char_data->char_id;
- data->server = map_id; //Update server where char is.
-
- //Reply with an ack.
- WFIFOW(fd, 0) = 0x2b06;
- memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
- WFIFOSET(fd, 30);
- } else { //Reply with nak
- WFIFOHEAD(fd, 30);
- WFIFOW(fd, 0) = 0x2b06;
- memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
- WFIFOL(fd, 6) = 0; //Set login1 to 0.
- WFIFOSET(fd, 30);
- }
- RFIFOSKIP(fd, 35);
- }
- break;
-
- // char name check
- case 0x2b08:
- if (RFIFOREST(fd) < 6)
- return 0;
- {
- char name[NAME_LENGTH];
- WFIFOHEAD(fd,30);
- char_loadName((int)RFIFOL(fd,2), name);
- WFIFOW(fd,0) = 0x2b09;
- WFIFOL(fd,2) = RFIFOL(fd,2);
- memcpy(WFIFOP(fd,6), name, NAME_LENGTH);
- WFIFOSET(fd,30);
- RFIFOSKIP(fd,6);
- }
- break;
-
- // I want become GM - fuck!
- case 0x2b0a:
- if(RFIFOREST(fd)<4)
- return 0;
- if(RFIFOREST(fd)<RFIFOW(fd,2))
- return 0;
- /*
- memcpy(WFIFOP(login_fd,2),RFIFOP(fd,2),RFIFOW(fd,2)-2);
- WFIFOW(login_fd,0)=0x2720;
- WFIFOSET(login_fd,RFIFOW(fd,2));
-// printf("char : change gm -> login %d %s %d\n", RFIFOL(fd, 4), RFIFOP(fd, 8), RFIFOW(fd, 2));
- */
- ShowWarning("packet 0x2ba (become GM) is not supported by the Char-Server.\n");
- RFIFOSKIP(fd, RFIFOW(fd, 2));
- break;
-
- // Map server send information to change an email of an account -> login-server
- case 0x2b0c:
- if (RFIFOREST(fd) < 86)
- return 0;
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 86);
- memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0), 86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
- WFIFOW(login_fd,0) = 0x2722;
- WFIFOSET(login_fd, 86);
- }
- RFIFOSKIP(fd, 86);
- break;
-
- // Receiving from map-server a status change resquest. Transmission to login-server (by Yor)
- case 0x2b0e:
- if (RFIFOREST(fd) < 44)
- return 0;
- {
- char character_name[NAME_LENGTH], t_name[NAME_LENGTH*2];
- int acc = RFIFOL(fd,2); // account_id of who ask (-1 if nobody)
- WFIFOHEAD(fd, 34);
- memcpy(character_name, RFIFOP(fd,6), NAME_LENGTH);
- character_name[NAME_LENGTH-1] = '\0';
- jstrescapecpy(t_name, character_name); //Escape string for sql use... [Skotlex]
- // prepare answer
- WFIFOW(fd,0) = 0x2b0f; // answer
- WFIFOL(fd,2) = acc; // who want do operation
- WFIFOW(fd,30) = RFIFOW(fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
- sprintf(tmp_sql, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'",char_db, t_name);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res) {
- if (mysql_num_rows(sql_res)) {
- sql_row = mysql_fetch_row(sql_res);
- memcpy(WFIFOP(fd,6), sql_row[1], NAME_LENGTH); // put correct name if found
- WFIFOW(fd,32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- switch(RFIFOW(fd, 30)) {
- case 1: // block
- if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = atoi(sql_row[0]); // account value
- WFIFOL(login_fd,6) = 5; // status of the account
- WFIFOSET(login_fd, 10);
- } else
- WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- } else
- WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- break;
- case 2: // ban
- if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 18);
- WFIFOW(login_fd, 0) = 0x2725;
- WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
- WFIFOW(login_fd, 6) = RFIFOW(fd,32); // year
- WFIFOW(login_fd, 8) = RFIFOW(fd,34); // month
- WFIFOW(login_fd,10) = RFIFOW(fd,36); // day
- WFIFOW(login_fd,12) = RFIFOW(fd,38); // hour
- WFIFOW(login_fd,14) = RFIFOW(fd,40); // minute
- WFIFOW(login_fd,16) = RFIFOW(fd,42); // second
- WFIFOSET(login_fd,18);
- } else
- WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- } else
- WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- break;
- case 3: // unblock
- if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = atoi(sql_row[0]); // account value
- WFIFOL(login_fd,6) = 0; // status of the account
- WFIFOSET(login_fd, 10);
- } else
- WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- } else
- WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- break;
- case 4: // unban
- if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 6);
- WFIFOW(login_fd, 0) = 0x272a;
- WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
- WFIFOSET(login_fd, 6);
- } else
- WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- } else
- WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- break;
- case 5: // changesex
- if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd, 6);
- WFIFOW(login_fd, 0) = 0x2727;
- WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
- WFIFOSET(login_fd, 6);
- } else
- WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- } else
- WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- break;
- }
- } else {
- // character name not found
- memcpy(WFIFOP(fd,6), character_name, NAME_LENGTH);
- WFIFOW(fd,32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
- }
- // send answer if a player ask, not if the server ask
- if (acc != -1) {
- WFIFOSET(fd, 34);
- }
- mysql_free_result(sql_res);
- }
- }
- RFIFOSKIP(fd, 44);
- break;
-
-// case 0x2b0f: Not used anymore, available for future use
-
- // Update and send fame ranking list [DracoRPG]
- case 0x2b10:
- if (RFIFOREST(fd) < 12)
- return 0;
- {
- int cid = RFIFOL(fd, 2);
- int fame = RFIFOL(fd, 6);
- char type = RFIFOB(fd, 10);
- char pos = RFIFOB(fd, 11);
- int size = 0;
- struct fame_list *list = NULL;
- RFIFOSKIP(fd,12);
-
- 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;
- }
- if(!size) break; //No list.
- if(pos)
- {
- pos--; //Convert from pos to index.
- if(
- (pos == 0 || fame < list[pos-1].fame) &&
- (pos == size-1 || fame > list[pos+1].fame)
- ) { //No change in order.
- list[(int)pos].fame = fame;
- char_send_fame_list(fd);
- break;
- }
- // If the player's already in the list, remove the entry and shift the following ones 1 step up
- memmove(list+pos, list+pos+1, (size-pos-1) * sizeof(struct fame_list));
- //Clear out last entry.
- list[size-1].id = 0;
- list[size-1].fame = 0;
- }
-
- // Find the position where the player has to be inserted
- for(i = 0; i < size && fame < list[i].fame; i++);
- if(i>=size) break; //Out of ranking.
- // When found someone with less or as much fame, insert just above
- memmove(list+i+1, list+i, (size-i-1) * sizeof(struct fame_list));
- list[i].id = cid;
- list[i].fame = fame;
- // Look for the player's name
- char_loadName(list[i].id, list[i].name);
- char_send_fame_list(-1);
- }
-
- break;
-
- // Receive rates [Wizputer]
- case 0x2b16:
- if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
- return 0;
- {
- char motd[256], t_name[512]; //Required for jstrescapecpy [Skotlex]
- strncpy(motd, RFIFOP(fd,10), 255); //First copy it to make sure the motd fits.
- motd[255]='\0';
- jstrescapecpy(t_name,motd);
-
- sprintf(tmp_sql, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d',`motd`='%s'",
- fd, server_name, RFIFOW(fd,2), RFIFOW(fd,4), RFIFOW(fd,6), t_name);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- RFIFOSKIP(fd,RFIFOW(fd,8));
- break;
- }
-
- // Character disconnected set online 0 [Wizputer]
- case 0x2b17:
- if (RFIFOREST(fd) < 6 )
- return 0;
- //printf("Setting %d char offline\n",RFIFOL(fd,2));
- set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
- RFIFOSKIP(fd,10);
- break;
- // Reset all chars to offline [Wizputer]
- case 0x2b18:
- set_all_offline(id);
- RFIFOSKIP(fd,2);
- break;
- // Character set online [Wizputer]
- case 0x2b19:
- if (RFIFOREST(fd) < 6 )
- return 0;
- set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
- RFIFOSKIP(fd,10);
- break;
-
- // Build and send fame ranking lists [DracoRPG]
- case 0x2b1a:
- if (RFIFOREST(fd) < 2)
- return 0;
- char_read_fame_list();
- char_send_fame_list(-1);
- RFIFOSKIP(fd,2);
- break;
-
- //Request saving sc_data of a player. [Skotlex]
- case 0x2b1c:
- if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
- return 0;
- {
-#ifdef ENABLE_SC_SAVING
- int count, aid, cid, i;
- struct status_change_data data;
- char *p = tmp_sql;
-
- aid = RFIFOL(fd, 4);
- cid = RFIFOL(fd, 8);
- count = RFIFOW(fd, 12);
-
- p+= sprintf(p, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
-
- for (i = 0; i < count; i++)
- {
- memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
- p += sprintf (p, " ('%d','%d','%hu','%d','%d','%d','%d','%d'),", aid, cid,
- data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
- }
- if (count > 0)
- {
- *--p = '\0'; //Remove final comma.
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-#endif
- RFIFOSKIP(fd, RFIFOW(fd, 2));
- break;
- }
-
- case 0x2736:
- if (RFIFOREST(fd) < 6) return 0;
- ShowInfo("Updated IP address of Server #%d to %d.%d.%d.%d.\n",id,
- (int)RFIFOB(fd,2),(int)RFIFOB(fd,3),
- (int)RFIFOB(fd,4),(int)RFIFOB(fd,5));
- server[id].ip = RFIFOL(fd, 2);
- RFIFOSKIP(fd,6);
- break;
-
- default:
- // inter server - packet
- {
- int r = inter_parse_frommap(fd);
- if (r == 1) break; // processed
- if (r == 2) return 0; // need more packet
- }
-
- // no inter server packet. no char server packet -> disconnect
- ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
- session[fd]->eof = 1;
- return 0;
- }
- }
- return 0;
-}
-
-int search_mapserver(unsigned short map, long ip, short port) {
- int i, j;
-
- if (!map)
- return -1;
-
- for(i = 0; i < MAX_MAP_SERVERS; i++)
- if (server_fd[i] > 0)
- for (j = 0; server[i].map[j]; j++)
- if (server[i].map[j] == map) {
- if (ip > 0 && server[i].ip != ip)
- continue;
- if (port > 0 && server[i].port != port)
- continue;
- return i;
- }
-
- return -1;
-}
-
-int char_mapif_init(int fd) {
- return inter_mapif_init(fd);
-}
-
-//--------------------------------------------
-// Test to know if an IP come from LAN or WAN.
-// Rewrote: Adnvanced subnet check [LuzZza]
-//--------------------------------------------
-int lan_subnetcheck(long *p) {
-
- int i;
- unsigned char *sbn, *msk, *src = (unsigned char *)p;
-
- for(i=0; i<subnet_count; i++) {
-
- if((subnet[i].subnet & subnet[i].mask) == (*p & subnet[i].mask)) {
-
- sbn = (unsigned char *)&subnet[i].subnet;
- msk = (unsigned char *)&subnet[i].mask;
-
- ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n",
- src[0], src[1], src[2], src[3], sbn[0], sbn[1], sbn[2], sbn[3], msk[0], msk[1], msk[2], msk[3]);
-
- return subnet[i].map_ip;
- }
- }
-
- ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", src[0], src[1], src[2], src[3]);
- return 0;
-}
-
-int parse_char(int fd) {
-
- int i, ch = 0;
- char email[40];
- unsigned char buf[64];
- unsigned short cmd;
- int map_fd;
- struct char_session_data *sd;
- unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr;
- long subnet_map_ip;
- RFIFOHEAD(fd);
-
- sd = (struct char_session_data*)session[fd]->session_data;
-
- if(login_fd < 0)
- session[fd]->eof = 1;
- if(session[fd]->eof) {
- if (fd == login_fd)
- login_fd = -1;
- if (sd != NULL)
- {
- struct online_char_data* data = idb_get(online_char_db, sd->account_id);
- if (!data || data->server== -1) //If it is not in any server, send it offline. [Skotlex]
- set_char_offline(99,sd->account_id);
- }
- do_close(fd);
- return 0;
- }
-
- while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
- cmd = RFIFOW(fd,0);
- // crc32‚ΜƒXƒLƒbƒv—p
- if( sd==NULL && // –’ƒƒOƒCƒ“orŠΗ—ƒpƒPƒbƒg
- RFIFOREST(fd)>=4 && // Ε’αƒoƒCƒg”§Œΐ • 0x7530,0x7532ŠΗ—ƒpƒPœ‹Ž
- RFIFOREST(fd)<=21 && // Ε‘εƒoƒCƒg”§Œΐ • ƒT[ƒo[ƒƒOƒCƒ“œ‹Ž
- cmd!=0x20b && // md5’Κ’mƒpƒPƒbƒgœ‹Ž
- (RFIFOREST(fd)<6 || RFIFOW(fd,4)==0x65) ){ // ŽŸ‚Ι‰½‚©ƒpƒPƒbƒg‚ͺ—ˆ‚Δ‚ι‚Θ‚ηAΪ‘±‚Ε‚Θ‚’‚Ζ‚Ύ‚ί
- RFIFOSKIP(fd,4);
- cmd = RFIFOW(fd,0);
- ShowDebug("parse_char : %d crc32 skipped\n",fd);
- if(RFIFOREST(fd)==0)
- return 0;
- }
-
-//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) { RFIFOSKIP(fd,rest); return 0; } }
-
- switch(cmd){
- case 0x20b: //20040622 encryption ragexe correspondence
- if (RFIFOREST(fd) < 19)
- return 0;
- RFIFOSKIP(fd,19);
- break;
-
- case 0x65: // request to connect
- ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10));
- if (RFIFOREST(fd) < 17)
- return 0;
- {
- WFIFOHEAD(fd, 4);
-
- if (sd) {
- //Received again auth packet for already authentified account?? Discard it.
- //TODO: Perhaps log this as a hack attempt?
- RFIFOSKIP(fd,17);
- break;
- }
- CREATE(session[fd]->session_data, struct char_session_data, 1);
- sd = (struct char_session_data*)session[fd]->session_data;
- sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server)
- sd->account_id = RFIFOL(fd, 2);
- sd->login_id1 = RFIFOL(fd, 6);
- sd->login_id2 = RFIFOL(fd, 10);
- sd->sex = RFIFOB(fd, 16);
-
- WFIFOL(fd, 0) = RFIFOL(fd, 2);
- WFIFOSET(fd, 4);
-
- for(i = 0; i < AUTH_FIFO_SIZE; i++) {
- if (auth_fifo[i].account_id == sd->account_id &&
- auth_fifo[i].login_id1 == sd->login_id1 &&
-#if CMP_AUTHFIFO_LOGIN2 != 0
- auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18
-#endif
- (!check_ip_flag || auth_fifo[i].ip == session[fd]->client_addr.sin_addr.s_addr) &&
- auth_fifo[i].delflag == 2) {
- auth_fifo[i].delflag = 1;
-
- if (online_check)
- { // check if character is not online already. [Skotlex]
- struct online_char_data* character;
- character = idb_get(online_char_db, sd->account_id);
-
- if (character)
- {
- if (character->server > -1)
- { //Character already online. KICK KICK KICK
- mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
- if (!character->waiting_disconnect)
- add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
- character->waiting_disconnect = 1;
- /* Not a good idea because this would trigger when you do a char-change from the map server! [Skotlex]
- } else { //Kick from char server.
- struct char_session_data *tsd;
- int i;
- for(i = 0; i < fd_max; i++) {
- if (session[i] && i != fd && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == sd->account_id)
- {
- WFIFOW(i,0) = 0x81;
- WFIFOB(i,2) = 2;
- WFIFOSET(i,3);
- break;
- }
- if (i == fd_max) //Shouldn't happen, but just in case.
- set_char_offline(99, sd->account_id);
- }
- */
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 8;
- WFIFOSET(fd,3);
- break;
- }
- }
- }
-
- if (max_connect_user == 0 || count_users() < max_connect_user) {
- if (login_fd > 0) { // don't send request if no login-server
- // request to login-server to obtain e-mail/time limit
- WFIFOHEAD(login_fd, 6);
- WFIFOW(login_fd,0) = 0x2716;
- WFIFOL(login_fd,2) = sd->account_id;
- WFIFOSET(login_fd,6);
- }
- // send characters to player
- mmo_char_send006b(fd, sd);
- } else {
- // refuse connection (over populated)
- WFIFOW(fd,0) = 0x6c;
- WFIFOW(fd,2) = 0;
- WFIFOSET(fd,3);
- }
-// printf("connection request> set delflag 1(o:2)- account_id:%d/login_id1:%d(fifo_id:%d)\n", sd->account_id, sd->login_id1, i);
- break;
- }
- }
- if (i == AUTH_FIFO_SIZE) {
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd,19);
- WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
- WFIFOL(login_fd,2) = sd->account_id;
- WFIFOL(login_fd,6) = sd->login_id1;
- WFIFOL(login_fd,10) = sd->login_id2;
- WFIFOB(login_fd,14) = sd->sex;
- WFIFOL(login_fd,15) = session[fd]->client_addr.sin_addr.s_addr;
- WFIFOSET(login_fd,19);
- } else { // if no login-server, we must refuse connection
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- }
- }
- }
- RFIFOSKIP(fd, 17);
- break;
-
- case 0x66: // char select
- FIFOSD_CHECK(3);
-
- sprintf(tmp_sql, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'",char_db, sd->account_id, RFIFOB(fd, 2));
- RFIFOSKIP(fd, 3);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
-
- if (sql_row)
- {
- int char_id = atoi(sql_row[0]);
- mysql_free_result(sql_res); //Free'd as soon as possible
- mmo_char_fromsql(char_id, &char_dat);
- char_dat.sex = sd->sex;
- } else {
- mysql_free_result(sql_res);
- break;
- }
-
- if (log_char) {
- char escaped_name[NAME_LENGTH*2];
- sprintf(tmp_sql,"INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
- charlog_db, sd->account_id, RFIFOB(fd, 2), jstrescapecpy(escaped_name, char_dat.name));
- //query
- if(mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- ShowInfo("Selected char: (Account %d: %d - %s)" RETCODE, sd->account_id, RFIFOB(fd, 2), char_dat.name);
-
- i = search_mapserver(char_dat.last_point.map, -1, -1);
-
- // if map is not found, we check major cities
- if (i < 0) {
- unsigned short j;
- //First check that there's actually a map server online.
- for(j = 0; j < MAX_MAP_SERVERS; j++)
- if (server_fd[j] >= 0 && server[j].map[0])
- break;
- if (j == MAX_MAP_SERVERS) {
- ShowInfo("Connection Closed. No map servers available.\n");
- WFIFOHEAD(fd, 3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
- char_dat.last_point.x = 273;
- char_dat.last_point.y = 354;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
- char_dat.last_point.x = 120;
- char_dat.last_point.y = 100;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
- char_dat.last_point.x = 160;
- char_dat.last_point.y = 94;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
- char_dat.last_point.x = 116;
- char_dat.last_point.y = 57;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
- char_dat.last_point.x = 87;
- char_dat.last_point.y = 117;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
- char_dat.last_point.x = 94;
- char_dat.last_point.y = 103;
- } else {
- ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(char_dat.last_point.map));
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(char_dat.last_point.map), mapindex_id2name(j));
- char_dat.last_point.map = j;
- }
- { //Send player to map.
- WFIFOHEAD(fd,28);
- WFIFOW(fd, 0) =0x71;
- WFIFOL(fd, 2) =char_dat.char_id;
- memcpy(WFIFOP(fd,6), mapindex_id2name(char_dat.last_point.map), MAP_NAME_LENGTH);
-
- // Advanced subnet check [LuzZza]
- if((subnet_map_ip = lan_subnetcheck((long *)p)))
- WFIFOL(fd,22) = subnet_map_ip;
- else
- WFIFOL(fd,22) = server[i].ip;
-
- WFIFOW(fd,26) = server[i].port;
- WFIFOSET(fd,28);
- }
- if (auth_fifo_pos >= AUTH_FIFO_SIZE) {
- auth_fifo_pos = 0;
- }
- auth_fifo[auth_fifo_pos].account_id = sd->account_id;
- auth_fifo[auth_fifo_pos].char_id = char_dat.char_id;
- auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1;
- auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2;
- auth_fifo[auth_fifo_pos].delflag = 0;
- auth_fifo[auth_fifo_pos].char_pos = 0;
- auth_fifo[auth_fifo_pos].sex = sd->sex;
- auth_fifo[auth_fifo_pos].connect_until_time = sd->connect_until_time;
- auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr.sin_addr.s_addr;
-
- //Send NEW auth packet [Kevin]
- if ((map_fd = server_fd[i]) < 1 || session[map_fd] == NULL)
- {
- ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
- server_fd[i] = -1;
- memset(&server[i], 0, sizeof(struct mmo_map_server));
- break;
- }
- { //Send auth ok to map server
- WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
- WFIFOW(map_fd,0) = 0x2afd;
- WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
- WFIFOL(map_fd,4) = auth_fifo[auth_fifo_pos].account_id;
- WFIFOL(map_fd,8) = auth_fifo[auth_fifo_pos].login_id1;
- WFIFOL(map_fd,16) = auth_fifo[auth_fifo_pos].login_id2;
- WFIFOL(map_fd,12) = (unsigned long)auth_fifo[auth_fifo_pos].connect_until_time;
- memcpy(WFIFOP(map_fd,20), &char_dat, sizeof(struct mmo_charstatus));
- WFIFOSET(map_fd, WFIFOW(map_fd,2));
- }
-
- set_char_online(i, auth_fifo[auth_fifo_pos].char_id, auth_fifo[auth_fifo_pos].account_id);
- //Checks to see if the even share setting of the party must be broken.
- inter_party_logged(char_dat.party_id, char_dat.account_id, char_dat.char_id);
- auth_fifo_pos++;
- break;
-
- case 0x67: // make new
- FIFOSD_CHECK(37);
-
- if(char_new == 0) //turn character creation on/off [Kevin]
- i = -2;
- else
- i = make_new_char_sql(fd, RFIFOP(fd, 2));
-
- //'Charname already exists' (-1), 'Char creation denied' (-2)
- //And 'You are underaged' (-3) (XD) [Sirius]
- if (i < 0)
- {
- WFIFOHEAD(fd, 3);
- WFIFOW(fd, 0) = 0x6e;
- switch (i) {
- case -1: WFIFOB(fd, 2) = 0x00; break;
- case -2: WFIFOB(fd, 2) = 0x02; break;
- case -3: WFIFOB(fd, 2) = 0x01; break;
- }
- WFIFOSET(fd, 3);
- RFIFOSKIP(fd, 37);
- break;
- }
- { //Send data.
- WFIFOHEAD(fd, 108);
- WFIFOW(fd, 0) = 0x6d;
- memset(WFIFOP(fd, 2), 0x00, 106);
-
- mmo_char_fromsql_short(i, &char_dat); //Only the short data is needed.
- WFIFOL(fd, 2) = char_dat.char_id;
- WFIFOL(fd,2+4) = char_dat.base_exp>LONG_MAX?LONG_MAX:char_dat.base_exp;
- WFIFOL(fd,2+8) = char_dat.zeny;
- WFIFOL(fd,2+12) = char_dat.job_exp>LONG_MAX?LONG_MAX:char_dat.job_exp;
- WFIFOL(fd,2+16) = char_dat.job_level;
-
- WFIFOL(fd,2+28) = char_dat.karma;
- WFIFOL(fd,2+32) = char_dat.manner;
-
- WFIFOW(fd,2+40) = 0x30;
- WFIFOW(fd,2+42) = (char_dat.hp > SHRT_MAX) ? SHRT_MAX : char_dat.hp;
- WFIFOW(fd,2+44) = (char_dat.max_hp > SHRT_MAX) ? SHRT_MAX : char_dat.max_hp;
- WFIFOW(fd,2+46) = (char_dat.sp > SHRT_MAX) ? SHRT_MAX : char_dat.sp;
- WFIFOW(fd,2+48) = (char_dat.max_sp > SHRT_MAX) ? SHRT_MAX : char_dat.max_sp;
- WFIFOW(fd,2+50) = DEFAULT_WALK_SPEED; // char_dat[i].speed;
- WFIFOW(fd,2+52) = char_dat.class_;
- WFIFOW(fd,2+54) = char_dat.hair;
-
- WFIFOW(fd,2+58) = char_dat.base_level;
- WFIFOW(fd,2+60) = (char_dat.skill_point > SHRT_MAX) ? SHRT_MAX : char_dat.skill_point;
-
- WFIFOW(fd,2+64) = char_dat.shield;
- WFIFOW(fd,2+66) = char_dat.head_top;
- WFIFOW(fd,2+68) = char_dat.head_mid;
- WFIFOW(fd,2+70) = char_dat.hair_color;
-
- memcpy(WFIFOP(fd,2+74), char_dat.name, NAME_LENGTH);
-
- WFIFOB(fd,2+98) = char_dat.str>UCHAR_MAX?UCHAR_MAX:char_dat.str;
- WFIFOB(fd,2+99) = char_dat.agi>UCHAR_MAX?UCHAR_MAX:char_dat.agi;
- WFIFOB(fd,2+100) = char_dat.vit>UCHAR_MAX?UCHAR_MAX:char_dat.vit;
- WFIFOB(fd,2+101) = char_dat.int_>UCHAR_MAX?UCHAR_MAX:char_dat.int_;
- WFIFOB(fd,2+102) = char_dat.dex>UCHAR_MAX?UCHAR_MAX:char_dat.dex;
- WFIFOB(fd,2+103) = char_dat.luk>UCHAR_MAX?UCHAR_MAX:char_dat.luk;
- WFIFOB(fd,2+104) = char_dat.char_num;
-
- WFIFOSET(fd, 108);
- RFIFOSKIP(fd, 37);
- }
- //to do
- for(ch = 0; ch < 9; ch++) {
- if (sd->found_char[ch] == -1) {
- sd->found_char[ch] = char_dat.char_id;
- break;
- }
- }
- break;
- case 0x68: /* delete char */
- FIFOSD_CHECK(46);
- {
- int cid = RFIFOL(fd,2);
- WFIFOHEAD(fd, 46);
- ShowInfo(CL_RED" Request Char Deletion:"CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
- memcpy(email, RFIFOP(fd,6), 40);
-
- /* Check if e-mail is correct */
- if(strcmpi(email, sd->email)){
- if(strcmp("a@a.com", sd->email) == 0){
- if(strcmp("a@a.com", email) == 0 || strcmp("", email) == 0){
- //ignore
- }else{
- //del fail
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- RFIFOSKIP(fd, 46);
- break;
- }
- }else{
- //del fail
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- RFIFOSKIP(fd, 46);
- break;
- }
- }
-
- for(i = 0; i < 9; i++) {
- /* Debug:
- printf("Checking if char to be deleted: %d - %d (%d)\n", sd->found_char[i], RFIFOL(fd, 2), sd->account_id);
- */
- if (sd->found_char[i] == cid) {
- for(ch = i; ch < 9-1; ch++)
- sd->found_char[ch] = sd->found_char[ch+1];
- sd->found_char[8] = -1;
- break;
- }
- }
- /* Such a character does not exist in the account */
- /* If so, you are so screwed. */
- if (i == 9) {
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- break;
- }
-
- /* Grab the partner id */
- sprintf(tmp_sql, "SELECT `partner_id` FROM `%s` WHERE `char_id`='%d'",char_db, cid);
-
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sql_res = mysql_store_result(&mysql_handle);
-
- if(sql_res)
- {
- int char_pid=0;
- sql_row = mysql_fetch_row(sql_res);
- if (sql_row)
- char_pid = atoi(sql_row[0]);
- mysql_free_result(sql_res);
-
- /* Delete character and partner (if any) */
- if(delete_char_sql(cid, char_pid)<0){
- //can't delete the char
- //either SQL error or can't delete by some CONFIG conditions
- //del fail
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- RFIFOSKIP(fd, 46);
- break;
- }
- if (char_pid != 0)
- { /* If there is partner, tell map server to do divorce */
- WBUFW(buf,0) = 0x2b12;
- WBUFL(buf,2) = RFIFOL(fd,2);
- WBUFL(buf,6) = char_pid;
- mapif_sendall(buf,10);
- }
- }
- /* Char successfully deleted.*/
- WFIFOW(fd, 0) = 0x6f;
- WFIFOSET(fd, 2);
-
- RFIFOSKIP(fd, 46);
- break;
- }
- case 0x2af8: // login as map-server
- if (RFIFOREST(fd) < 60)
- return 0;
- {
- char *l_userid = RFIFOP(fd,2);
- char *l_password = RFIFOP(fd,26);
- WFIFOHEAD(fd, 4+5*GM_num);
-
- l_userid[23] = '\0';
- l_password[23] = '\0';
- WFIFOW(fd, 0) = 0x2af9;
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if (server_fd[i] <= 0)
- break;
- }
- if (i == MAX_MAP_SERVERS ||
- strcmp(l_userid, userid) ||
- strcmp(l_password, passwd)) {
- WFIFOB(fd,2) = 3;
- WFIFOSET(fd, 3);
- } else {
- int len;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd, 3);
- session[fd]->func_parse = parse_frommap;
- server_fd[i] = fd;
- server[i].ip = RFIFOL(fd, 54);
- server[i].port = RFIFOW(fd, 58);
- server[i].users = 0;
- memset(server[i].map, 0, sizeof(server[i].map));
- realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
- char_mapif_init(fd);
- // send gm acccounts level to map-servers
- len = 4;
- WFIFOW(fd,0) = 0x2b15;
- for(i = 0; i < GM_num; i++) {
- WFIFOL(fd,len) = gm_account[i].account_id;
- WFIFOB(fd,len+4) = (unsigned char)gm_account[i].level;
- len += 5;
- }
- WFIFOW(fd,2) = len;
- WFIFOSET(fd,len);
- }
- RFIFOSKIP(fd,60);
- break;
- }
- case 0x187: // Alive?
- if (RFIFOREST(fd) < 6) {
- return 0;
- }
- RFIFOSKIP(fd, 6);
- break;
-
- case 0x7530: // Athena info get
- {
- WFIFOHEAD(fd, 10);
- WFIFOW(fd, 0) = 0x7531;
- WFIFOB(fd, 2) = ATHENA_MAJOR_VERSION;
- WFIFOB(fd, 3) = ATHENA_MINOR_VERSION;
- WFIFOB(fd, 4) = ATHENA_REVISION;
- WFIFOB(fd, 5) = ATHENA_RELEASE_FLAG;
- WFIFOB(fd, 6) = ATHENA_OFFICIAL_FLAG;
- WFIFOB(fd, 7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR;
- WFIFOW(fd, 8) = ATHENA_MOD_VERSION;
- WFIFOSET(fd, 10);
- RFIFOSKIP(fd, 2);
- return 0;
- }
- case 0x7532: // disconnect(default also disconnect)
- default:
- session[fd]->eof = 1;
- return 0;
- }
- }
- RFIFOFLUSH(fd);
-
- return 0;
-}
-
-// Console Command Parser [Wizputer]
-int parse_console(char *buf) {
- char *type,*command;
-
- type = (char *)aMalloc(64);
- command = (char *)aMalloc(64);
-
- memset(type,0,64);
- memset(command,0,64);
-
- ShowNotice("Console: %s\n",buf);
-
- if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 )
- sscanf(buf,"%[^\n]",type);
-
- ShowNotice("Type of command: %s || Command: %s \n",type,command);
-
- if(buf) aFree(buf);
- if(type) aFree(type);
- if(command) aFree(command);
-
- return 0;
-}
-
-// MAP send all
-int mapif_sendall(unsigned char *buf, unsigned int len) {
- int i, c;
- int fd;
-
- c = 0;
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if ((fd = server_fd[i]) > 0) { //0 Should not be a valid server_fd [Skotlex]
- WFIFOHEAD(fd,len);
-#if 0 //This seems to have been fixed long long ago.
- if (session[fd] == NULL)
- { //Could this be the crash's source? [Skotlex]
- ShowError("mapif_sendall: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", fd, i);
- server_fd[i] = -1;
- memset(&server[i], 0, sizeof(struct mmo_map_server));
- continue;
- }
-#endif
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- c++;
- }
- }
-
- return c;
-}
-
-int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) {
- int i, c;
- int fd;
-
- c = 0;
- for(i=0, c=0;i<MAX_MAP_SERVERS;i++){
- if ((fd = server_fd[i]) > 0 && fd != sfd) {
- WFIFOHEAD(fd, len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd, len);
- c++;
- }
- }
-
- return c;
-}
-
-int mapif_send(int fd, unsigned char *buf, unsigned int len) {
- int i;
-
- if (fd >= 0) {
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if (fd == server_fd[i]) {
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- return 1;
- }
- }
- }
- return 0;
-}
-
-int send_users_tologin(int tid, unsigned int tick, int id, int data) {
- int users = count_users();
- unsigned char buf[16];
-
- if (login_fd > 0 && session[login_fd]) {
- // send number of user to login server
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x2714;
- WFIFOL(login_fd,2) = users;
- WFIFOSET(login_fd,6);
- }
- // send number of players to all map-servers
- WBUFW(buf,0) = 0x2b00;
- WBUFL(buf,2) = users;
- mapif_sendall(buf, 6);
-
- return 0;
-}
-
-static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) {
- struct online_char_data* character = (struct online_char_data*)data;
- int *i = va_arg(ap, int*);
- int count = va_arg(ap, int);
- if ((*i) >= count)
- return 0; //This is an error that shouldn't happen....
- if(character->server > -1) {
- WFIFOHEAD(login_fd, 8+count*4);
- WFIFOL(login_fd, 8+(*i)*4) =character->account_id;
- (*i)++;
- return 1;
- }
- return 0;
-}
-
-int send_accounts_tologin(int tid, unsigned int tick, int id, int data) {
- int users = count_users(), i=0;
-
- if (login_fd > 0 && session[login_fd]) {
- // send account list to login server
- WFIFOHEAD(login_fd, 8+users*4);
- WFIFOW(login_fd,0) = 0x272d;
- WFIFOL(login_fd,4) = users;
- online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users);
- WFIFOW(login_fd,2) = 8+ i*4;
- WFIFOSET(login_fd,WFIFOW(login_fd,2));
- }
- return 0;
-}
-
-int check_connect_login_server(int tid, unsigned int tick, int id, int data) {
- if (login_fd > 0 && session[login_fd] != NULL)
- return 0;
-
- ShowInfo("Attempt to connect to login-server...\n");
- login_fd = make_connection(login_ip, login_port);
- if (login_fd == -1)
- { //Try again later. [Skotlex]
- login_fd = 0;
- return 0;
- }
- session[login_fd]->func_parse = parse_tologin;
- realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
- {
- WFIFOHEAD(login_fd, 86);
- WFIFOW(login_fd,0) = 0x2710;
- memcpy(WFIFOP(login_fd,2), userid, 24);
- memcpy(WFIFOP(login_fd,26), passwd, 24);
- WFIFOL(login_fd,50) = 0;
- WFIFOL(login_fd,54) = char_ip;
- WFIFOL(login_fd,58) = char_port;
- memcpy(WFIFOP(login_fd,60), server_name, 20);
- WFIFOW(login_fd,80) = 0;
- WFIFOW(login_fd,82) = char_maintenance;
- WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
- WFIFOSET(login_fd,86);
- }
- return 0;
-}
-
-//------------------------------------------------
-//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, int data)
-{
- struct online_char_data* character;
- if ((character = idb_get(online_char_db, id)) != NULL && character->waiting_disconnect)
- { //Mark it offline due to timeout.
- set_char_offline(character->char_id, character->account_id);
- }
- return 0;
-}
-
-//----------------------------------------------------------
-// Return numerical value of a switch configuration by [Yor]
-// on/off, english, franηais, deutsch, espaρol
-//----------------------------------------------------------
-int config_switch(const char *str) {
- if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
- return 1;
- if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
- return 0;
-
- return atoi(str);
-}
-
-//----------------------------------
-// Reading Lan Support configuration
-// Rewrote: Anvanced subnet check [LuzZza]
-//----------------------------------
-int char_lan_config_read(const char *lancfgName) {
-
- FILE *fp;
- int line_num = 0;
- char line[1024], w1[64], w2[64], w3[64], w4[64];
-
- if((fp = fopen(lancfgName, "r")) == NULL) {
- ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
- return 1;
- }
-
- ShowInfo("Reading the configuration file %s...\n", lancfgName);
-
- while(fgets(line, sizeof(line)-1, fp)) {
-
- line_num++;
- if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
- continue;
-
- line[sizeof(line)-1] = '\0';
- if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) {
-
- ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
- continue;
- }
-
- remove_control_chars((unsigned char *)w1);
- remove_control_chars((unsigned char *)w2);
- remove_control_chars((unsigned char *)w3);
- remove_control_chars((unsigned char *)w4);
-
- if(strcmpi(w1, "subnet") == 0) {
-
- subnet[subnet_count].mask = inet_addr(w2);
- subnet[subnet_count].char_ip = inet_addr(w3);
- subnet[subnet_count].map_ip = inet_addr(w4);
- subnet[subnet_count].subnet = subnet[subnet_count].char_ip&subnet[subnet_count].mask;
- if (subnet[subnet_count].subnet != (subnet[subnet_count].map_ip&subnet[subnet_count].mask)) {
- ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
- continue;
- }
-
- subnet_count++;
- }
-
- ShowStatus("Read information about %d subnetworks.\n", subnet_count);
- }
-
- fclose(fp);
- return 0;
-}
-
-void do_final(void) {
- ShowInfo("Doing final stage...\n");
- //inter_save();
- do_final_itemdb();
- //check SQL save progress.
- //wait until save char complete
-
- set_all_offline(-1);
- set_all_offline_sql();
-
- inter_final();
-
- flush_fifos();
-
- mapindex_final();
-
- sprintf(tmp_sql,"DELETE FROM `ragsrvinfo");
- if (mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- if(gm_account) {
- aFree(gm_account);
- gm_account = 0;
- }
-
- delete_session(login_fd);
- delete_session(char_fd);
- char_db_->destroy(char_db_, NULL);
- online_char_db->destroy(online_char_db, NULL);
-
- mysql_close(&mysql_handle);
- if(char_gm_read)
- mysql_close(&lmysql_handle);
-
- ShowInfo("ok! all done...\n");
-}
-#endif //TXT_SQL_CONVERT
-void sql_config_read(const char *cfgName){ /* Kalaspuff, to get login_db */
- char line[1024], w1[1024], w2[1024];
- FILE *fp;
-
- ShowInfo("Reading file %s...\n", cfgName);
-
- if ((fp = fopen(cfgName, "r")) == NULL) {
- ShowFatalError("file not found: %s\n", cfgName);
- exit(1);
- }
-
- while(fgets(line, sizeof(line)-1, fp)){
- if(line[0] == '/' && line[1] == '/')
- continue;
-
- if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
- continue;
-
- if(strcmpi(w1,"char_db")==0){
- strcpy(char_db,w2);
-#ifndef TXT_SQL_CONVERT
- } else if(strcmpi(w1, "gm_read_method") == 0) {
- if(atoi(w2) != 0)
- char_gm_read = true;
- else
- char_gm_read = false;
- //custom columns for login database
- }else if(strcmpi(w1,"login_db")==0){
- strcpy(login_db, w2);
- }else if(strcmpi(w1,"login_db_level")==0){
- strcpy(login_db_level,w2);
- }else if(strcmpi(w1,"login_db_account_id")==0){
- strcpy(login_db_account_id,w2);
- }else if(strcmpi(w1,"lowest_gm_level")==0){
- lowest_gm_level = atoi(w2);
- ShowStatus("set lowest_gm_level : %s\n",w2);
-#endif
- }else if(strcmpi(w1,"scdata_db")==0){
- strcpy(scdata_db,w2);
- }else if(strcmpi(w1,"cart_db")==0){
- strcpy(cart_db,w2);
- }else if(strcmpi(w1,"inventory_db")==0){
- strcpy(inventory_db,w2);
- }else if(strcmpi(w1,"charlog_db")==0){
- strcpy(charlog_db,w2);
- }else if(strcmpi(w1,"storage_db")==0){
- strcpy(storage_db,w2);
- }else if(strcmpi(w1,"reg_db")==0){
- strcpy(reg_db,w2);
- }else if(strcmpi(w1,"skill_db")==0){
- strcpy(skill_db,w2);
- }else if(strcmpi(w1,"interlog_db")==0){
- strcpy(interlog_db,w2);
- }else if(strcmpi(w1,"memo_db")==0){
- strcpy(memo_db,w2);
- }else if(strcmpi(w1,"guild_db")==0){
- strcpy(guild_db,w2);
- }else if(strcmpi(w1,"guild_alliance_db")==0){
- strcpy(guild_alliance_db,w2);
- }else if(strcmpi(w1,"guild_castle_db")==0){
- strcpy(guild_castle_db,w2);
- }else if(strcmpi(w1,"guild_expulsion_db")==0){
- strcpy(guild_expulsion_db,w2);
- }else if(strcmpi(w1,"guild_member_db")==0){
- strcpy(guild_member_db,w2);
- }else if(strcmpi(w1,"guild_skill_db")==0){
- strcpy(guild_skill_db,w2);
- }else if(strcmpi(w1,"guild_position_db")==0){
- strcpy(guild_position_db,w2);
- }else if(strcmpi(w1,"guild_storage_db")==0){
- strcpy(guild_storage_db,w2);
- }else if(strcmpi(w1,"party_db")==0){
- strcpy(party_db,w2);
- }else if(strcmpi(w1,"pet_db")==0){
- strcpy(pet_db,w2);
- }else if(strcmpi(w1,"friend_db")==0){
- strcpy(friend_db,w2);
-#ifndef TXT_SQL_CONVERT
- }else if(strcmpi(w1,"db_path")==0){
- strcpy(db_path,w2);
- //Map server option to use SQL db or not
- }else if(strcmpi(w1,"use_sql_db")==0){ // added for sql item_db read for char server [Valaris]
- db_use_sqldbs = config_switch(w2);
- ShowStatus("Using SQL dbs: %s\n",w2);
- }else if(strcmpi(w1,"item_db_db")==0){
- strcpy(item_db_db,w2);
- }else if(strcmpi(w1,"item_db2_db")==0){
- strcpy(item_db2_db,w2);
- } else if(strcmpi(w1,"connection_ping_interval")==0) {
- connection_ping_interval = config_switch(w2);
-#endif
- //support the import command, just like any other config
- }else if(strcmpi(w1,"import")==0){
- sql_config_read(w2);
- }
-
- }
- fclose(fp);
- ShowInfo("done reading %s.\n", cfgName);
-}
-#ifndef TXT_SQL_CONVERT
-
-int char_config_read(const char *cfgName) {
- char line[1024], w1[1024], w2[1024];
- FILE *fp;
-
- if ((fp = fopen(cfgName, "r")) == NULL) {
- ShowFatalError("Configuration file not found: %s.\n", cfgName);
- exit(1);
- }
-
- ShowInfo("Reading file %s...\n", cfgName);
- while(fgets(line, sizeof(line)-1, fp)) {
- if (line[0] == '/' && line[1] == '/')
- continue;
-
- line[sizeof(line)-1] = '\0';
- if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2)
- continue;
-
- remove_control_chars((unsigned char *) w1);
- remove_control_chars((unsigned char *) w2);
- if(strcmpi(w1,"timestamp_format")==0) {
- strncpy(timestamp_format, w2, 20);
- } else if(strcmpi(w1,"console_silent")==0){
- msg_silent = 0; //To always allow the next line to show up.
- ShowInfo("Console Silent Setting: %d\n", atoi(w2));
- msg_silent = atoi(w2);
- } else if(strcmpi(w1,"stdout_with_ansisequence")==0){
- stdout_with_ansisequence = config_switch(w2);
- } else if (strcmpi(w1, "userid") == 0) {
- strncpy(userid, w2, 24);
- } else if (strcmpi(w1, "passwd") == 0) {
- strncpy(passwd, w2, 24);
- } else if (strcmpi(w1, "server_name") == 0) {
- strncpy(server_name, w2, 20);
- server_name[sizeof(server_name) - 1] = '\0';
- ShowStatus("%s server has been initialized\n", w2);
- } else if (strcmpi(w1, "wisp_server_name") == 0) {
- if (strlen(w2) >= 4) {
- memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
- wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
- }
- } else if (strcmpi(w1, "login_ip") == 0) {
- unsigned char ip_str[16];
- login_ip = resolve_hostbyname(w2, NULL, ip_str);
- if (login_ip) {
- strncpy(login_ip_str, w2, sizeof(login_ip_str));
- ShowStatus("Login server IP address : %s -> %s\n", w2, ip_str);
- }
- } else if (strcmpi(w1, "login_port") == 0) {
- login_port=atoi(w2);
- } else if (strcmpi(w1, "char_ip") == 0) {
- unsigned char ip_str[16];
- char_ip = resolve_hostbyname(w2, NULL, ip_str);
- if (char_ip){
- strncpy(char_ip_str, w2, sizeof(char_ip_str));
- ShowStatus("Character server IP address : %s -> %s\n", w2, ip_str);
- }
- } else if (strcmpi(w1, "bind_ip") == 0) {
- unsigned char ip_str[16];
- bind_ip = resolve_hostbyname(w2, NULL, ip_str);
- if (bind_ip) {
- strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
- ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip_str);
- }
- } 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_new")==0){
- char_new = atoi(w2);
- } else if (strcmpi(w1, "char_new_display")==0){
- char_new_display = atoi(w2);
- } else if (strcmpi(w1, "max_connect_user") == 0) {
- max_connect_user = atoi(w2);
- if (max_connect_user < 0)
- max_connect_user = 0; // unlimited online players
- } else if(strcmpi(w1, "gm_allow_level") == 0) {
- gm_allow_level = atoi(w2);
- if(gm_allow_level < 0)
- gm_allow_level = 99;
- } else if (strcmpi(w1, "check_ip_flag") == 0) {
- check_ip_flag = config_switch(w2);
- } else if (strcmpi(w1, "online_check") == 0) {
- online_check = config_switch(w2);
- } else if (strcmpi(w1, "autosave_time") == 0) {
- autosave_interval = atoi(w2)*1000;
- if (autosave_interval <= 0)
- autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
- } else if (strcmpi(w1, "save_log") == 0) {
- save_log = config_switch(w2);
- } else if (strcmpi(w1, "start_point") == 0) {
- char map[MAP_NAME_LENGTH];
- int x, y;
- if (sscanf(w2,"%16[^,],%d,%d", map, &x, &y) < 3)
- continue;
- if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
- 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;
- start_point.y = y;
- }
- } else if (strcmpi(w1, "start_zeny") == 0) {
- start_zeny = atoi(w2);
- if (start_zeny < 0)
- start_zeny = 0;
- } else if (strcmpi(w1, "start_weapon") == 0) {
- start_weapon = atoi(w2);
- if (start_weapon < 0)
- start_weapon = 0;
- } else if (strcmpi(w1, "start_armor") == 0) {
- start_armor = atoi(w2);
- if (start_armor < 0)
- start_armor = 0;
- } else if(strcmpi(w1,"log_char")==0){ //log char or not [devil]
- log_char = atoi(w2);
- } else if (strcmpi(w1, "unknown_char_name") == 0) {
- strcpy(unknown_char_name, w2);
- unknown_char_name[NAME_LENGTH-1] = 0;
- } else if (strcmpi(w1, "name_ignoring_case") == 0) {
- name_ignoring_case = config_switch(w2);
- } else if (strcmpi(w1, "char_name_option") == 0) {
- char_name_option = atoi(w2);
- } else if (strcmpi(w1, "char_name_letters") == 0) {
- strcpy(char_name_letters, w2);
- } else if (strcmpi(w1, "check_ip_flag") == 0) {
- check_ip_flag = config_switch(w2);
- } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
- char_per_account = atoi(w2);
- } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
- char_del_level = atoi(w2);
- } else if (strcmpi(w1, "console") == 0) {
- if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 )
- console = 1;
- } else if (strcmpi(w1, "fame_list_alchemist") == 0) {
- fame_list_size_chemist = atoi(w2);
- if (fame_list_size_chemist > MAX_FAME_LIST) {
- ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST);
- fame_list_size_chemist = MAX_FAME_LIST;
- }
- } else if (strcmpi(w1, "fame_list_blacksmith") == 0) {
- fame_list_size_smith = atoi(w2);
- if (fame_list_size_smith > MAX_FAME_LIST) {
- ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST);
- fame_list_size_smith = MAX_FAME_LIST;
- }
- } else if (strcmpi(w1, "fame_list_taekwon") == 0) {
- fame_list_size_taekwon = atoi(w2);
- if (fame_list_size_taekwon > MAX_FAME_LIST) {
- ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST);
- fame_list_size_taekwon = MAX_FAME_LIST;
- }
- } else if (strcmpi(w1, "guild_exp_rate") == 0) {
- guild_exp_rate = atoi(w2);
- } else if (strcmpi(w1, "import") == 0) {
- char_config_read(w2);
- }
- }
- fclose(fp);
-
- ShowInfo("Done reading %s.\n", cfgName);
-
- return 0;
-}
-
-void set_server_type(void)
-{
- SERVER_TYPE = ATHENA_SERVER_CHAR;
-}
-
-static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
-{
- struct online_char_data *character= (struct online_char_data*)data;
- if (character->server == -2) //Unknown server.. set them offline
- set_char_offline(character->char_id, character->account_id);
- if (character->server < 0)
- //Free data from players that have not been online for a while.
- db_remove(online_char_db, key);
- return 0;
-}
-
-static int online_data_cleanup(int tid, unsigned int tick, int id, int data)
-{
- online_char_db->foreach(online_char_db, online_data_cleanup_sub);
- return 0;
-}
-
-int do_init(int argc, char **argv){
- int i;
-
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- memset(&server[i], 0, sizeof(struct mmo_map_server));
- server_fd[i] = -1;
- }
-
- //Read map indexes
- mapindex_init();
- start_point.map = mapindex_name2id("new_zone01.gat");
-
- 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);
-
- if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) {
- ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n");
- ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n");
- ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n");
- }
-
- ShowInfo("Finished reading the char-server configuration.\n");
-
- inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server ΓΚ±βΘ­
- ShowInfo("Finished reading the inter-server configuration.\n");
-
- //Read ItemDB
- do_init_itemdb();
-
- ShowInfo("Initializing char server.\n");
- online_char_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
- mmo_char_sql_init();
- ShowInfo("char server initialized.\n");
-
-// ShowDebug("set parser -> parse_char()...\n");
- set_defaultparse(parse_char);
-
-// ShowDebug("set terminate function -> do_final().....\n");
-
- if ((naddr_ != 0) && (!login_ip || !char_ip)) {
- // The char server should know what IP address it is running on
- // - MouseJstr
- int localaddr = ntohl(addr_[0]);
- unsigned char *ptr = (unsigned char *) &localaddr;
- char buf[16];
- sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
- if (naddr_ != 1)
- ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", buf);
- else
- ShowStatus("Defaulting to %s as our IP address\n", buf);
- if (!login_ip) {
- strcpy(login_ip_str, buf);
- login_ip = inet_addr(login_ip_str);
- }
- if (!char_ip) {
- strcpy(char_ip_str, buf);
- char_ip = inet_addr(char_ip_str);
- }
- if (ptr[0] == 192 && ptr[1] == 168)
- ShowWarning("Firewall detected.. edit subnet_athena.conf and char_athena.conf\n");
- }
-
- ShowInfo("open port %d.....\n",char_port);
- char_fd = make_listen_bind(bind_ip?bind_ip:INADDR_ANY,char_port);
-
- add_timer_func_list(check_connect_login_server, "check_connect_login_server");
- add_timer_func_list(send_users_tologin, "send_users_tologin");
- add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
- add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
-
- add_timer_func_list(online_data_cleanup, "online_data_cleanup");
- add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600 * 1000);
-
- // send ALIVE PING to login server.
- add_timer_interval(gettick() + 10, check_connect_login_server, 0, 0, 10 * 1000);
- // send USER COUNT PING to login server.
- add_timer_interval(gettick() + 10, send_users_tologin, 0, 0, 5 * 1000);
- add_timer_interval(gettick() + 3600*1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour.
-
- char_read_fame_list(); //Read fame lists.
-
- if(char_gm_read)
- read_gm_account();
-
-
- if ( console ) {
- set_defaultconsoleparse(parse_console);
- start_console();
- }
-
- //Cleaning the tables for NULL entrys @ startup [Sirius]
- //Chardb clean
- ShowInfo("Cleaning the '%s' table...\n", char_db);
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `account_id` = '0'", char_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- //guilddb clean
- ShowInfo("Cleaning the '%s' table...\n", guild_db);
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- //guildmemberdb clean
- ShowInfo("Cleaning the '%s' table...\n", guild_member_db);
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db);
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- ShowInfo("End of char server initilization function.\n");
- ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port);
- return 0;
-}
-
-#undef mysql_query
-
-int debug_mysql_query(char *file, int line, void *mysql, const char *q) {
-#ifdef TWILIGHT
- ShowDebug("sql: %s:%d# %s\n", file, line, q);
-#endif
- return mysql_query((MYSQL *) mysql, q);
-}
-
-int char_child(int parent_id, int child_id) {
- int tmp_id = 0;
- sprintf (tmp_sql, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id);
- if (mysql_query (&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result (&mysql_handle);
- sql_row = sql_res?mysql_fetch_row (sql_res):NULL;
- if (sql_row)
- tmp_id = atoi (sql_row[0]);
- else
- ShowError("CHAR: child Failed!\n");
- if (sql_res) mysql_free_result (sql_res);
- if ( tmp_id == child_id )
- return 1;
- else
- return 0;
-}
-
-int char_married(int pl1,int pl2) {
- int tmp_id = 0;
- sprintf (tmp_sql, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1);
- if (mysql_query (&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result (&mysql_handle);
- sql_row = sql_res?mysql_fetch_row (sql_res):NULL;
- if (sql_row)
- tmp_id = atoi (sql_row[0]);
- else
- ShowError("CHAR: married Failed!\n");
- if (sql_res) mysql_free_result (sql_res);
- if ( tmp_id == pl2 )
- return 1;
- else
- return 0;
-}
-
-int char_family(int pl1,int pl2,int pl3) {
- int charid, partnerid, childid;
- sprintf (tmp_sql, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, pl1, pl2, pl3);
- if (mysql_query (&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- sql_res = mysql_store_result (&mysql_handle);
- if (!sql_res) return 0;
-
- while((sql_row = mysql_fetch_row(sql_res)))
- {
- charid = atoi(sql_row[0]);
- partnerid = atoi(sql_row[1]);
- childid = atoi(sql_row[2]);
- if (charid == pl1) {
- if ((pl2 == partnerid && pl3 == childid) ||
- (pl3 == partnerid && pl2 == childid)
- ) {
- mysql_free_result (sql_res);
- return childid;
- }
- }
- if(charid == pl2) {
- if ((pl1 == partnerid && pl3 == childid) ||
- (pl3 == partnerid && pl1 == childid)
- ) {
- mysql_free_result (sql_res);
- return childid;
- }
- }
- if(charid == pl3) {
- if ((pl1 == partnerid && pl2 == childid) ||
- (pl2 == partnerid && pl1 == childid)
- ) {
- mysql_free_result (sql_res);
- return childid;
- }
- }
- }
- mysql_free_result (sql_res);
- return 0;
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by Jioh L. Jung
+// TXT 1.105
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "char.h"
+#include "../common/utils.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+#include "itemdb.h"
+#include "inter.h"
+#include "db.h"
+#include "malloc.h"
+#include "int_guild.h"
+
+#ifndef TXT_SQL_CONVERT
+static struct dbt *char_db_;
+#endif
+char char_db[256] = "char";
+char scdata_db[256] = "sc_data";
+char cart_db[256] = "cart_inventory";
+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";
+char guild_alliance_db[256] = "guild_alliance";
+char guild_castle_db[256] = "guild_castle";
+char guild_expulsion_db[256] = "guild_expulsion";
+char guild_member_db[256] = "guild_member";
+char guild_position_db[256] = "guild_position";
+char guild_skill_db[256] = "guild_skill";
+char guild_storage_db[256] = "guild_storage";
+char party_db[256] = "party";
+char pet_db[256] = "pet";
+char friend_db[256] = "friends";
+#ifdef TXT_SQL_CONVERT
+int save_log = 0; //Have the logs be off by default when converting
+#else
+int save_log = 1;
+int db_use_sqldbs;
+int connection_ping_interval = 0;
+
+char login_db[256] = "login";
+char login_db_account_id[32] = "account_id";
+char login_db_level[32] = "level";
+
+int lowest_gm_level = 1;
+
+char *SQL_CONF_NAME = "conf/inter_athena.conf";
+
+struct mmo_map_server{
+ long ip;
+ short port;
+ int users;
+ unsigned short map[MAX_MAP_PER_SERVER];
+} server[MAX_MAP_SERVERS];
+
+int server_fd[MAX_MAP_SERVERS];
+
+int login_fd, char_fd;
+char userid[24];
+char passwd[24];
+char server_name[20];
+char wisp_server_name[NAME_LENGTH] = "Server";
+char login_ip_str[128];
+in_addr_t login_ip = 0;
+int login_port = 6900;
+char char_ip_str[128];
+in_addr_t char_ip = 0;
+char bind_ip_str[128];
+in_addr_t bind_ip = 0;
+int char_port = 6121;
+int char_maintenance = 0;
+int char_new;
+int char_new_display;
+int name_ignoring_case = 0; // 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]
+char char_name_letters[1024] = ""; // list of letters/symbols used to authorise or not a name of a character. by [Yor]
+//The following are characters that are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
+#define TRIM_CHARS "\032\t\x0A\x0D "
+int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
+int char_del_level = 0; //From which level u can delete character [Lupus]
+
+int log_char = 1; // loggin char or not [devil]
+int log_inter = 1; // loggin inter or not [devil]
+
+// Advanced subnet check [LuzZza]
+struct _subnet {
+ long subnet;
+ long mask;
+ long char_ip;
+ long map_ip;
+} subnet[16];
+
+int subnet_count = 0;
+
+char unknown_char_name[NAME_LENGTH] = "Unknown";
+char db_path[1024]="db";
+
+//These are used to aid the map server in identifying valid clients. [Skotlex]
+static int max_account_id = DEFAULT_MAX_ACCOUNT_ID, max_char_id = DEFAULT_MAX_CHAR_ID;
+static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex]
+
+struct char_session_data{
+ int account_id, login_id1, login_id2,sex;
+ int found_char[9];
+ char email[40]; // e-mail (default: a@a.com) by [Yor]
+ time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
+};
+
+#define AUTH_FIFO_SIZE 256
+struct {
+ int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag,sex;
+ time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
+} auth_fifo[AUTH_FIFO_SIZE];
+int auth_fifo_pos = 0;
+
+int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system)
+
+struct mmo_charstatus char_dat;
+int char_num,char_max;
+int max_connect_user = 0;
+int gm_allow_level = 99;
+int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
+int start_zeny = 0;
+int start_weapon = 1201;
+int start_armor = 2301;
+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_taekwon = MAX_FAME_LIST;
+
+// Char-server-side stored fame lists [DracoRPG]
+struct fame_list smith_fame_list[MAX_FAME_LIST];
+struct fame_list chemist_fame_list[MAX_FAME_LIST];
+struct fame_list taekwon_fame_list[MAX_FAME_LIST];
+
+// check for exit signal
+// 0 is saving complete
+// other is char_id
+unsigned int save_flag = 0;
+
+// start point (you can reset point on conf file)
+struct point start_point = { 0, 53, 111};
+
+bool char_gm_read = false;
+struct gm_account *gm_account = NULL;
+int GM_num = 0;
+
+int console = 0;
+
+//Structure for holding in memory which characters are online on the map servers connected.
+struct online_char_data {
+ int account_id;
+ int char_id;
+ short server;
+ unsigned waiting_disconnect :1;
+};
+
+struct dbt *online_char_db; //Holds all online characters.
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data);
+
+static void * create_online_char_data(DBKey key, va_list args) {
+ struct online_char_data* character;
+ character = aCalloc(1, sizeof(struct online_char_data));
+ character->account_id = key.i;
+ character->char_id = -1;
+ character->server = -1;
+ return character;
+}
+
+//-------------------------------------------------
+// Set Character online/offline [Wizputer]
+//-------------------------------------------------
+
+void set_char_online(int map_id, int char_id, int account_id) {
+ struct online_char_data* character;
+ if ( char_id != 99 ) {
+ sprintf(tmp_sql, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d'",char_db,char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ if (max_account_id < account_id || max_char_id < char_id)
+ { //Notify map-server of the new max IDs [Skotlex]
+ if (account_id > max_account_id)
+ max_account_id = account_id;
+ if (char_id > max_char_id)
+ max_char_id = char_id;
+ mapif_send_maxid(max_account_id, max_char_id);
+ }
+ }
+
+ character = idb_ensure(online_char_db, account_id, create_online_char_data);
+ if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id)
+ {
+ //char == 99 <- Character logging in, so someone has logged in while one
+ //char is still on map-server, so kick him out, but don't print "error"
+ //as this is normal behaviour. [Skotlex]
+ if (char_id != 99)
+ ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n",
+ character->account_id, character->char_id, character->server, map_id, account_id, char_id);
+ mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
+ }
+ character->char_id = (char_id==99)?-1:char_id;
+ character->server = (char_id==99)?-1:map_id;
+ character->waiting_disconnect = 0;
+ if (char_id != 99)
+ { //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it.
+ struct mmo_charstatus *cp;
+ cp = idb_get(char_db_,char_id);
+ inter_guild_CharOnline(char_id, cp?cp->guild_id:-1);
+ }
+ if (login_fd > 0 && !session[login_fd]->eof)
+ {
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x272b;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ }
+}
+
+void set_char_offline(int char_id, int account_id) {
+ struct mmo_charstatus *cp;
+ struct online_char_data* character;
+
+ if ( char_id == 99 )
+ sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id);
+ else {
+ cp = idb_get(char_db_,char_id);
+ inter_guild_CharOffline(char_id, cp?cp->guild_id:-1);
+ if (cp)
+ idb_remove(char_db_,char_id);
+
+ sprintf(tmp_sql,"UPDATE `%s` SET `online`='0' WHERE `char_id`='%d'", char_db, char_id);
+
+ if (mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ if ((character = idb_get(online_char_db, account_id)) != NULL)
+ { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex]
+ character->char_id = -1;
+ character->server = -1;
+ character->waiting_disconnect = 0;
+ }
+
+ if (login_fd > 0 && !session[login_fd]->eof)
+ {
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x272c;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ }
+}
+
+static int char_db_setoffline(DBKey key, void* data, va_list ap) {
+ struct online_char_data* character = (struct online_char_data*)data;
+ int server = va_arg(ap, int);
+ if (server == -1) {
+ character->char_id = -1;
+ character->server = -1;
+ character->waiting_disconnect = 0;
+ } else if (character->server == server)
+ character->server = -2; //In some map server that we aren't connected to.
+ return 0;
+}
+
+static int char_db_kickoffline(DBKey key, void* data, va_list ap) {
+ struct online_char_data* character = (struct online_char_data*)data;
+ int server = va_arg(ap, int);
+ if (server > -1 && character->server != server)
+ return 0;
+
+ //Kick out any connected characters, and set them offline as appropiate.
+ if (character->server > -1)
+ mapif_disconnectplayer(server_fd[character->server],
+ character->account_id, character->char_id, 1);
+ else if (!character->waiting_disconnect)
+ set_char_offline(character->char_id, character->account_id);
+ else return 0;
+ return 1;
+}
+
+void set_all_offline(int id) {
+ if (id < 0)
+ ShowNotice("Sending all users offline.\n");
+ else
+ ShowNotice("Sending users of map-server %d offline.\n",id);
+ online_char_db->foreach(online_char_db,char_db_kickoffline,id);
+
+ if (id >= 0 || login_fd <= 0 || session[login_fd]->eof)
+ return;
+ //Tell login-server to also mark all our characters as offline.
+ WFIFOHEAD(login_fd, 2);
+ WFIFOW(login_fd,0) = 0x2737;
+ WFIFOSET(login_fd,2);
+}
+
+void set_all_offline_sql(void) {
+ //Set all players to 'OFFLINE'
+ sprintf(tmp_sql, "UPDATE `%s` SET `online` = '0'", char_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql, "UPDATE `%s` SET `online` = '0'", guild_member_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql, "UPDATE `%s` SET `connect_member` = '0'", guild_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+}
+
+//----------------------------------------------------------------------
+// Determine if an account (id) is a GM account
+// and returns its level (or 0 if it isn't a GM account or if not found)
+//----------------------------------------------------------------------
+// Removed since nothing GM related goes on in the char server [CLOWNISIUS]
+int isGM(int account_id) {
+ int i;
+
+ for(i = 0; i < GM_num; i++)
+ if (gm_account[i].account_id == account_id)
+ return gm_account[i].level;
+ return 0;
+}
+
+void read_gm_account(void) {
+ if(!char_gm_read)
+ return;
+
+ if (gm_account != NULL)
+ aFree(gm_account);
+ GM_num = 0;
+
+ sprintf(tmp_sql, "SELECT `%s`,`%s` FROM `%s` WHERE `%s`>='%d'",login_db_account_id,login_db_level,login_db,login_db_level,lowest_gm_level);
+ if (mysql_query(&lmysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&lmysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ lsql_res = mysql_store_result(&lmysql_handle);
+ if (lsql_res) {
+ gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * (size_t)mysql_num_rows(lsql_res), 1);
+ while ((lsql_row = mysql_fetch_row(lsql_res))) {
+ gm_account[GM_num].account_id = atoi(lsql_row[0]);
+ gm_account[GM_num].level = atoi(lsql_row[1]);
+ GM_num++;
+ }
+ }
+
+ mysql_free_result(lsql_res);
+ mapif_send_gmaccounts();
+}
+#endif //TXT_SQL_CONVERT
+int compare_item(struct item *a, struct item *b) {
+
+ if(a->id == b->id &&
+ a->nameid == b->nameid &&
+ a->amount == b->amount &&
+ a->equip == b->equip &&
+ a->identify == b->identify &&
+ a->refine == b->refine &&
+ a->attribute == b->attribute)
+ {
+ int i;
+ for (i=0; i<MAX_SLOTS && a->card[i]==b->card[i]; i++);
+ return (i == MAX_SLOTS);
+ }
+ return 0;
+}
+
+#ifndef TXT_SQL_CONVERT
+static void* create_charstatus(DBKey key, va_list args) {
+ struct mmo_charstatus *cp;
+ cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus));
+ cp->char_id = key.i;
+ return cp;
+}
+#endif //TXT_SQL_CONVERT
+int mmo_char_tosql(int char_id, struct mmo_charstatus *p){
+ int i=0,j;
+ int count = 0;
+ int diff = 0;
+ char *tmp_ptr; //Building a single query should be more efficient than running
+ //multiple queries for each thing about to be saved, right? [Skotlex]
+ char save_status[128]; //For displaying save information. [Skotlex]
+ struct mmo_charstatus *cp;
+ struct itemtmp mapitem[MAX_GUILD_STORAGE];
+
+ if (char_id!=p->char_id) return 0;
+
+#ifndef TXT_SQL_CONVERT
+ cp = idb_ensure(char_db_, char_id, create_charstatus);
+#else
+ cp = aCalloc(1, sizeof(struct mmo_charstatus));
+#endif
+
+ memset(save_status, 0, sizeof(save_status));
+ diff = 0;
+ //map inventory data
+ for(i=0;i<MAX_INVENTORY;i++){
+ if (!compare_item(&p->inventory[i], &cp->inventory[i]))
+ diff = 1;
+ if(p->inventory[i].nameid>0){
+ mapitem[count].flag=0;
+ mapitem[count].id = p->inventory[i].id;
+ mapitem[count].nameid=p->inventory[i].nameid;
+ mapitem[count].amount = p->inventory[i].amount;
+ mapitem[count].equip = p->inventory[i].equip;
+ mapitem[count].identify = p->inventory[i].identify;
+ mapitem[count].refine = p->inventory[i].refine;
+ mapitem[count].attribute = p->inventory[i].attribute;
+ for (j=0; j<MAX_SLOTS; j++)
+ mapitem[count].card[j] = p->inventory[i].card[j];
+ count++;
+ }
+ }
+ //printf("- Save item data to MySQL!\n");
+ if (diff)
+ if (!memitemdata_to_sql(mapitem, count, p->char_id,TABLE_INVENTORY))
+ strcat(save_status, " inventory");
+
+ count = 0;
+ diff = 0;
+
+ //map cart data
+ for(i=0;i<MAX_CART;i++){
+ if (!compare_item(&p->cart[i], &cp->cart[i]))
+ diff = 1;
+ if(p->cart[i].nameid>0){
+ mapitem[count].flag=0;
+ mapitem[count].id = p->cart[i].id;
+ mapitem[count].nameid=p->cart[i].nameid;
+ mapitem[count].amount = p->cart[i].amount;
+ mapitem[count].equip = p->cart[i].equip;
+ mapitem[count].identify = p->cart[i].identify;
+ mapitem[count].refine = p->cart[i].refine;
+ mapitem[count].attribute = p->cart[i].attribute;
+ for (j=0; j<MAX_SLOTS; j++)
+ mapitem[count].card[j] = p->cart[i].card[j];
+ count++;
+ }
+ }
+
+ if (diff)
+ if (!memitemdata_to_sql(mapitem, count, p->char_id,TABLE_CART))
+ strcat(save_status, " cart");
+#ifdef TXT_SQL_CONVERT
+{ //Insert the barebones to then update the rest.
+ char t_name[NAME_LENGTH*2];
+ jstrescapecpy(t_name, p->name);
+ sprintf(tmp_sql, "REPLACE INTO `%s` (`account_id`, `char_num`, `name`) VALUES ('%d', '%d', '%s')",
+ char_db, p->account_id, p->char_num, t_name);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " creation");
+}
+#endif
+
+ if (
+ (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) ||
+ (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) ||
+ (p->zeny != cp->zeny) ||
+ (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) ||
+ (p->max_hp != cp->max_hp) || (p->hp != cp->hp) ||
+ (p->max_sp != cp->max_sp) || (p->sp != cp->sp) ||
+ (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) ||
+ (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) ||
+ (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) ||
+ (p->option != cp->option) ||
+ (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) ||
+ (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) ||
+ (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
+ (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom)
+ )
+ { //Save status
+ sprintf(tmp_sql ,"UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
+ "`base_exp`='%u', `job_exp`='%u', `zeny`='%d',"
+ "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d',"
+ "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d',"
+ "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," //[orn] add homun_id (homunculus id)
+ "`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'"
+ " WHERE `account_id`='%d' AND `char_id` = '%d'",
+ char_db, p->base_level, p->job_level,
+ p->base_exp, p->job_exp, p->zeny,
+ p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point,
+ p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
+ p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, //[orn] add homun_id (homunculus id)
+ p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
+ 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->account_id, p->char_id
+ );
+
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " status");
+ }
+
+ //Values that will seldom change (to speed up saving)
+ if (
+ (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) ||
+ (p->class_ != cp->class_) ||
+ (p->partner_id != cp->partner_id) || (p->father != cp->father) ||
+ (p->mother != cp->mother) || (p->child != cp->child) ||
+ (p->karma != cp->karma) || (p->manner != cp->manner) ||
+ (p->fame != cp->fame)
+ )
+ {
+ sprintf(tmp_sql ,"UPDATE `%s` SET `class`='%d',"
+ "`hair`='%d',`hair_color`='%d',`clothes_color`='%d',"
+ "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d',"
+ "`karma`='%d',`manner`='%d', `fame`='%d'"
+ " WHERE `account_id`='%d' AND `char_id` = '%d'",
+ char_db, p->class_,
+ p->hair, p->hair_color, p->clothes_color,
+ p->partner_id, p->father, p->mother, p->child,
+ p->karma, p->manner, p->fame,
+ p->account_id, p->char_id
+ );
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " status2");
+ }
+
+
+ diff = 0;
+
+ for(i=0;i<MAX_MEMOPOINTS;i++){
+ if(p->memo_point[i].map == cp->memo_point[i].map && p->memo_point[i].x == cp->memo_point[i].x && p->memo_point[i].y == cp->memo_point[i].y)
+ continue;
+ diff = 1;
+ break;
+ }
+
+ if (diff)
+ { //Save memo
+ //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",memo_db, p->char_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ //insert here.
+ tmp_ptr = tmp_sql;
+ tmp_ptr += sprintf(tmp_ptr, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db);
+ count = 0;
+ for(i=0;i<MAX_MEMOPOINTS;i++){
+ if(p->memo_point[i].map){
+ tmp_ptr += sprintf(tmp_ptr,"('%d', '%s', '%d', '%d'),",
+ char_id, mapindex_id2name(p->memo_point[i].map), p->memo_point[i].x, p->memo_point[i].y);
+ count++;
+ }
+ }
+ if (count)
+ { //Dangerous? Only if none of the above sprintf worked. [Skotlex]
+ tmp_ptr[-1] = '\0'; //Remove the trailing comma.
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " memo");
+ } else //Memo Points cleared (how is this possible?).
+ strcat(save_status, " memo");
+ }
+
+ diff = 0;
+ for(i=0;i<MAX_SKILL;i++) {
+ if ((p->skill[i].lv != 0) && (p->skill[i].id == 0))
+ p->skill[i].id = i; // Fix skill tree
+
+ if((p->skill[i].id != cp->skill[i].id) || (p->skill[i].lv != cp->skill[i].lv) ||
+ (p->skill[i].flag != cp->skill[i].flag))
+ {
+ diff = 1;
+ break;
+ }
+ }
+
+ if (diff)
+ { //Save skills
+
+ //`skill` (`char_id`, `id`, `lv`)
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",skill_db, p->char_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ tmp_ptr = tmp_sql;
+ tmp_ptr += sprintf(tmp_ptr,"INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db);
+ count = 0;
+ //insert here.
+ for(i=0;i<MAX_SKILL;i++){
+ if(p->skill[i].id && p->skill[i].flag!=1)
+ {
+ tmp_ptr += sprintf(tmp_ptr,"('%d','%d','%d'),",
+ char_id, p->skill[i].id, (p->skill[i].flag==0)?p->skill[i].lv:p->skill[i].flag-2);
+ count++;
+ }
+ }
+
+ if (count)
+ {
+ tmp_ptr[-1] = '\0'; //Remove trailing comma.
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " skills");
+ } else //Skills removed (reset?)
+ strcat(save_status, " skills");
+ }
+ diff = 0;
+ for(i = 0; i < MAX_FRIENDS; i++){
+ if(p->friends[i].char_id != cp->friends[i].char_id ||
+ p->friends[i].account_id != cp->friends[i].account_id){
+ diff = 1;
+ break;
+ }
+ }
+
+ if(diff == 1)
+ { //Save friends
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ tmp_ptr = tmp_sql;
+ tmp_ptr += sprintf(tmp_ptr, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db);
+ count = 0;
+ for(i = 0; i < MAX_FRIENDS; i++){
+ if(p->friends[i].char_id > 0)
+ {
+ tmp_ptr += sprintf(tmp_ptr, "('%d','%d','%d'),", char_id, p->friends[i].account_id, p->friends[i].char_id);
+ count++;
+ }
+ }
+ if (count)
+ {
+ tmp_ptr[-1] = '\0'; //Remove the last comma. [Skotlex]
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else
+ strcat(save_status, " friends");
+ } else //Friend list cleared.
+ strcat(save_status, " friends");
+
+ }
+
+ if (save_status[0]!='\0' && save_log)
+ ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status);
+#ifndef TXT_SQL_CONVERT
+ memcpy(cp, p, sizeof(struct mmo_charstatus));
+#else
+ aFree(cp);
+#endif
+ return 0;
+}
+
+// [Ilpalazzo-sama]
+int memitemdata_to_sql(struct itemtmp mapitem[], int count, int char_id, int tableswitch)
+{
+ int i,j, flag, id;
+ char *tablename;
+ char selectoption[16];
+ char * str_p = tmp_sql;
+
+ switch (tableswitch) {
+ case TABLE_INVENTORY:
+ tablename = inventory_db; // no need for sprintf here as *_db are char*.
+ sprintf(selectoption,"char_id");
+ break;
+ case TABLE_CART:
+ tablename = cart_db;
+ sprintf(selectoption,"char_id");
+ break;
+ case TABLE_STORAGE:
+ tablename = storage_db;
+ sprintf(selectoption,"account_id");
+ break;
+ case TABLE_GUILD_STORAGE:
+ tablename = guild_storage_db;
+ sprintf(selectoption,"guild_id");
+ break;
+ default:
+ ShowError("Invalid table name!\n");
+ return 1;
+ }
+
+ //=======================================mysql database data > memory===============================================
+
+ str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+
+ for (j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`", j);
+
+ str_p += sprintf(str_p, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, char_id);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 1;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ while ((sql_row = mysql_fetch_row(sql_res))) {
+ flag = 0;
+ id = atoi(sql_row[0]);
+ for(i = 0; i < count; i++) {
+ if(mapitem[i].flag == 1)
+ continue;
+ if(mapitem[i].nameid == atoi(sql_row[1])
+ && mapitem[i].card[0] == atoi(sql_row[7])
+ && mapitem[i].card[2] == atoi(sql_row[9])
+ && mapitem[i].card[3] == atoi(sql_row[10])
+ ) { //They are the same item.
+ for (j = 0; j<MAX_SLOTS && mapitem[i].card[j] == atoi(sql_row[7+j]); j++);
+ if (j == MAX_SLOTS &&
+ mapitem[i].amount == atoi(sql_row[2]) &&
+ mapitem[i].equip == atoi(sql_row[3]) &&
+ mapitem[i].identify == atoi(sql_row[4]) &&
+ mapitem[i].refine == atoi(sql_row[5]) &&
+ mapitem[i].attribute == atoi(sql_row[6]))
+ { //Do nothing.
+ } else
+//==============================================Memory data > SQL ===============================
+#ifndef TXT_SQL_CONVERT
+ if(!itemdb_isequip(mapitem[i].nameid))
+ { //Quick update of stackable items. Update Qty and Equip should be enough, but in case we are also updating identify
+ sprintf(tmp_sql,"UPDATE `%s` SET `equip`='%d', `identify`='%d', `amount`='%d' WHERE `id`='%d' LIMIT 1",
+ tablename, mapitem[i].equip, mapitem[i].identify,mapitem[i].amount, id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ } else
+#endif //TXT_SQL_CONVERT
+ { //Equipment or Misc item, just update all fields.
+ str_p = tmp_sql;
+ str_p += sprintf(str_p,"UPDATE `%s` SET `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d'",
+ tablename, mapitem[i].equip, mapitem[i].identify, mapitem[i].refine, mapitem[i].attribute);
+
+ for(j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`=%d", j, mapitem[i].card[j]);
+
+ str_p += sprintf(str_p,", `amount`='%d' WHERE `id`='%d' LIMIT 1",
+ mapitem[i].amount, id);
+
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ flag = mapitem[i].flag = 1; //Item dealt with,
+ break; //skip to next item in the db.
+ }
+ }
+ if(!flag) { //Item not updated, remove it.
+ sprintf(tmp_sql,"DELETE from `%s` where `id`='%d'", tablename, id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ mysql_free_result(sql_res);
+ }
+
+ for(i = 0; i < count; i++) {
+ if(!mapitem[i].flag) {
+ str_p = tmp_sql;
+ str_p += sprintf(str_p,"INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`",
+ tablename, selectoption);
+ for(j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p,", `card%d`", j);
+
+ str_p += sprintf(str_p,") VALUES ( '%d','%d', '%d', '%d', '%d', '%d', '%d'",
+ char_id, mapitem[i].nameid, mapitem[i].amount, mapitem[i].equip, mapitem[i].identify, mapitem[i].refine,
+ mapitem[i].attribute);
+
+ for(j=0; j<MAX_SLOTS; j++)
+ str_p +=sprintf(str_p,", '%d'",mapitem[i].card[j]);
+
+ strcat(tmp_sql, ")");
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+//=====================================================================================================
+int mmo_char_fromsql(int char_id, struct mmo_charstatus *p){
+ int i,j, n;
+ double exp;
+ char t_msg[128];
+ char *str_p = tmp_sql;
+ struct mmo_charstatus *cp;
+
+ memset(p, 0, sizeof(struct mmo_charstatus));
+ t_msg[0]= '\0';
+
+ p->char_id = char_id;
+ if (save_log)
+ ShowInfo("Char load request (%d)\n", char_id);
+ //`char`( `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, //9
+ //`str`,`agi`,`vit`,`int`,`dex`,`luk`, //15
+ //`max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, //21
+ //`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`, //27
+ //`hair`,`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, //35
+ //`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`)
+ //splite 2 parts. cause veeeery long SQL syntax
+
+ sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
+ "`str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ sql_row = mysql_fetch_row(sql_res);
+ if (!sql_row)
+ { //Just how does this happens? [Skotlex]
+ ShowError("Requested non-existant character id: %d!\n", char_id);
+ return 0;
+ }
+
+ p->char_id = char_id;
+ p->account_id = atoi(sql_row[1]);
+ p->char_num = atoi(sql_row[2]);
+ strcpy(p->name, sql_row[3]);
+ p->class_ = atoi(sql_row[4]);
+ p->base_level = atoi(sql_row[5]);
+ p->job_level = atoi(sql_row[6]);
+ exp = atof(sql_row[7]);
+ p->base_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
+ exp = atof(sql_row[8]);
+ p->job_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
+ p->zeny = atoi(sql_row[9]);
+ p->str = atoi(sql_row[10]);
+ p->agi = atoi(sql_row[11]);
+ p->vit = atoi(sql_row[12]);
+ p->int_ = atoi(sql_row[13]);
+ p->dex = atoi(sql_row[14]);
+ p->luk = atoi(sql_row[15]);
+ p->max_hp = atoi(sql_row[16]);
+ p->hp = atoi(sql_row[17]);
+ p->max_sp = atoi(sql_row[18]);
+ p->sp = atoi(sql_row[19]);
+ p->status_point = atoi(sql_row[20]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[20]);
+ p->skill_point = atoi(sql_row[21]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[21]);
+ //free mysql result.
+ mysql_free_result(sql_res);
+ strcat (t_msg, " status");
+ } else
+ ShowError("Load char failed (%d - table %s).\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
+
+ sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_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`, `homun_id`" //[orn] homun_id
+ "FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
+ if (sql_row) {
+
+ p->option = atoi(sql_row[0]); p->karma = atoi(sql_row[1]); p->manner = atoi(sql_row[2]);
+ p->party_id = atoi(sql_row[3]); p->guild_id = atoi(sql_row[4]); p->pet_id = atoi(sql_row[5]);
+
+ p->hair = atoi(sql_row[6]); p->hair_color = atoi(sql_row[7]); p->clothes_color = atoi(sql_row[8]);
+ p->weapon = atoi(sql_row[9]); p->shield = atoi(sql_row[10]);
+ p->head_top = atoi(sql_row[11]); p->head_mid = atoi(sql_row[12]); p->head_bottom = atoi(sql_row[13]);
+ p->last_point.map = mapindex_name2id(sql_row[14]); p->last_point.x = atoi(sql_row[15]); p->last_point.y = atoi(sql_row[16]);
+ p->save_point.map = mapindex_name2id(sql_row[17]); p->save_point.x = atoi(sql_row[18]); p->save_point.y = atoi(sql_row[19]);
+ p->partner_id = atoi(sql_row[20]); p->father = atoi(sql_row[21]); p->mother = atoi(sql_row[22]); p->child = atoi(sql_row[23]);
+ p->fame = atoi(sql_row[24]);
+ p->hom_id = atoi(sql_row[25]); //[orn] homunculus id
+
+ strcat (t_msg, " status2");
+ } else
+ ShowError("Char load failed (%d - table %s)\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
+ //free mysql result.
+ if (sql_res)
+ mysql_free_result(sql_res);
+
+ //read memo data
+ //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`)
+ sprintf(tmp_sql, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`='%d' ORDER by `memo_id`",memo_db, char_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
+ p->memo_point[i].map = mapindex_name2id(sql_row[0]);
+ p->memo_point[i].x=atoi(sql_row[1]);
+ p->memo_point[i].y=atoi(sql_row[2]);
+ //i ++;
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " memo");
+ }
+
+ //read inventory
+ //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
+ str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+
+ for (j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`", j);
+
+ str_p += sprintf(str_p, " FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
+ p->inventory[i].id = atoi(sql_row[0]);
+ p->inventory[i].nameid = atoi(sql_row[1]);
+ p->inventory[i].amount = atoi(sql_row[2]);
+ p->inventory[i].equip = atoi(sql_row[3]);
+ p->inventory[i].identify = atoi(sql_row[4]);
+ p->inventory[i].refine = atoi(sql_row[5]);
+ p->inventory[i].attribute = atoi(sql_row[6]);
+ for (j=0; j<MAX_SLOTS; j++)
+ p->inventory[i].card[j] = atoi(sql_row[7+j]);
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " inventory");
+ }
+
+ //read cart.
+ //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
+ str_p = tmp_sql;
+ str_p += sprintf(str_p, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
+
+ for (j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`", j);
+
+ str_p += sprintf(str_p, " FROM `%s` WHERE `char_id`='%d'", cart_db, char_id);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
+ p->cart[i].id = atoi(sql_row[0]);
+ p->cart[i].nameid = atoi(sql_row[1]);
+ p->cart[i].amount = atoi(sql_row[2]);
+ p->cart[i].equip = atoi(sql_row[3]);
+ p->cart[i].identify = atoi(sql_row[4]);
+ p->cart[i].refine = atoi(sql_row[5]);
+ p->cart[i].attribute = atoi(sql_row[6]);
+ for(j=0; j<MAX_SLOTS; j++)
+ p->cart[i].card[j] = atoi(sql_row[7+j]);
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " cart");
+ }
+
+ //read skill
+ //`skill` (`char_id`, `id`, `lv`)
+ sprintf(tmp_sql, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`='%d'",skill_db, char_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
+ n = atoi(sql_row[0]);
+ p->skill[n].id = n; //memory!? shit!.
+ p->skill[n].lv = atoi(sql_row[1]);
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " skills");
+ }
+/* Global-reg loading is now handled by the inter-server.
+ //global_reg
+ //`global_reg_value` (`char_id`, `str`, `value`)
+ sprintf(tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ i = 0;
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ for(i=0;(sql_row = mysql_fetch_row(sql_res));i++){
+ strcpy (p->global_reg[i].str, sql_row[0]);
+ strcpy (p->global_reg[i].value, sql_row[1]);
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " reg_values");
+ }
+ p->global_reg_num=i;
+*/
+ //Shamelessly stolen from its_sparky (ie: thanks) and then assimilated by [Skotlex]
+ //Friend list
+ sprintf(tmp_sql, "SELECT f.friend_account, f.friend_id, c.name FROM `%s` f LEFT JOIN `%s` c ON f.friend_account=c.account_id AND f.friend_id=c.char_id WHERE f.char_id='%d'", friend_db, char_db, char_id);
+
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+ if(sql_res)
+ {
+ for(i = 0; (sql_row = mysql_fetch_row(sql_res)) && i<MAX_FRIENDS; i++)
+ {
+ if(sql_row) { //need to check if we have sql_row before we check if we have sql_row[2] because we don't want a segfault
+ if(sql_row[2]) {
+ p->friends[i].account_id = atoi(sql_row[0]);
+ p->friends[i].char_id = atoi(sql_row[1]);
+ strncpy(p->friends[i].name, sql_row[2], NAME_LENGTH-1); //The -1 is to avoid losing the ending \0 [Skotlex]
+ }
+ }
+ }
+ mysql_free_result(sql_res);
+ strcat (t_msg, " friends");
+ }
+
+ if (save_log)
+ ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
+
+ cp = idb_ensure(char_db_, char_id, create_charstatus);
+ memcpy(cp, p, sizeof(struct mmo_charstatus));
+ return 1;
+}
+
+// For quick selection of data when displaying the char menu. [Skotlex]
+//
+int mmo_char_fromsql_short(int char_id, struct mmo_charstatus *p){
+ char t_msg[128];
+ double exp;
+ memset(p, 0, sizeof(struct mmo_charstatus));
+ t_msg[0]= '\0';
+
+ p->char_id = char_id;
+// ShowInfo("Quick Char load request (%d)\n", char_id);
+ //`char`( `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, //9
+ //`str`,`agi`,`vit`,`int`,`dex`,`luk`, //15
+ //`max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, //21
+ //`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`, //27
+ //`hair`,`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, //35
+ //`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`)
+ //splite 2 parts. cause veeeery long SQL syntax
+
+ sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,"
+ "`str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point` FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ sql_row = mysql_fetch_row(sql_res);
+ if (!sql_row)
+ { //Just how does this happens? [Skotlex]
+ ShowError("Requested non-existant character id: %d!\n", char_id);
+ mysql_free_result(sql_res);
+ return 0;
+ }
+ p->char_id = char_id;
+ p->account_id = atoi(sql_row[1]);
+ p->char_num = atoi(sql_row[2]);
+ strcpy(p->name, sql_row[3]);
+ p->class_ = atoi(sql_row[4]);
+ p->base_level = atoi(sql_row[5]);
+ p->job_level = atoi(sql_row[6]);
+ exp = atof(sql_row[7]);
+ p->base_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
+ exp = atof(sql_row[8]);
+ p->job_exp = exp<0?0:(exp>UINT_MAX?UINT_MAX:(unsigned int)exp);
+ p->zeny = atoi(sql_row[9]);
+ p->str = atoi(sql_row[10]);
+ p->agi = atoi(sql_row[11]);
+ p->vit = atoi(sql_row[12]);
+ p->int_ = atoi(sql_row[13]);
+ p->dex = atoi(sql_row[14]);
+ p->luk = atoi(sql_row[15]);
+ p->max_hp = atoi(sql_row[16]);
+ p->hp = atoi(sql_row[17]);
+ p->max_sp = atoi(sql_row[18]);
+ p->sp = atoi(sql_row[19]);
+ p->status_point = atoi(sql_row[20]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[20]);
+ p->skill_point = atoi(sql_row[21]) > USHRT_MAX ? USHRT_MAX : atoi(sql_row[21]);
+ //free mysql result.
+ mysql_free_result(sql_res);
+ strcat (t_msg, " status");
+ } else
+ ShowError("Load char failed (%d - table %s).\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
+
+ sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`hair`,`hair_color`,"
+ "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`"
+ "FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
+ if (sql_row) {
+
+ p->option = atoi(sql_row[0]); p->karma = atoi(sql_row[1]); p->manner = atoi(sql_row[2]);
+ p->hair = atoi(sql_row[3]); p->hair_color = atoi(sql_row[4]); p->clothes_color = atoi(sql_row[5]);
+ p->weapon = atoi(sql_row[6]); p->shield = atoi(sql_row[7]);
+ p->head_top = atoi(sql_row[8]); p->head_mid = atoi(sql_row[9]); p->head_bottom = atoi(sql_row[10]);
+
+ strcat (t_msg, " status2");
+ } else
+ ShowError("Char load failed (%d - table %s)\n", char_id, char_db); //Error?! ERRRRRR WHAT THAT SAY!?
+ //free mysql result.
+ if (sql_res)
+ mysql_free_result(sql_res);
+// if (save_log) //Too much spam :/
+// ShowInfo("Quick Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
+
+ return 1;
+}
+//==========================================================================================================
+int mmo_char_sql_init(void) {
+ ShowInfo("Begin Initializing.......\n");
+ char_db_= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA, sizeof(int));
+ // memory initialize
+ memset(&char_dat, 0, sizeof(struct mmo_charstatus));
+ if(char_per_account == 0){
+ ShowStatus("Chars per Account: 'Unlimited'.......\n");
+ }else{
+ ShowStatus("Chars per Account: '%d'.......\n", char_per_account);
+ }
+
+ //the 'set offline' part is now in check_login_conn ...
+ //if the server connects to loginserver
+ //it will dc all off players
+ //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)
+ set_all_offline_sql();
+
+ ShowInfo("Finished initilizing.......\n");
+
+ return 0;
+}
+
+//==========================================================================================================
+
+int make_new_char_sql(int fd, unsigned char *dat) {
+ struct char_session_data *sd;
+ char name[NAME_LENGTH];
+ char t_name[NAME_LENGTH*2];
+ unsigned int i; // Used in for loop and comparing with strlen, safe to be unsigned. [Lance]
+ int char_id, temp;
+
+ strncpy(name, dat, NAME_LENGTH);
+ name[NAME_LENGTH-1] = '\0'; //Always terminate string.
+ trim(name,TRIM_CHARS); //Trim character name. [Skotlex]
+ jstrescapecpy(t_name, name);
+
+ // disabled until fixed >.>
+ // Note: escape characters should be added to jstrescape()!
+ //mysql_real_escape_string(&mysql_handle, t_name, t_name_temp, sizeof(t_name_temp));
+
+ if (!session_isValid(fd) || !(sd = (struct char_session_data*)session[fd]->session_data))
+ return -2;
+
+ ShowInfo("New character request (%d)\n", sd->account_id);
+
+ //check name != main chat nick [LuzZza]
+ if(strcmpi(name, main_chat_nick) == 0) {
+ ShowInfo("Create char failed (%d): this nick (%s) reserved for mainchat messages.\n", sd->account_id, name);
+ return -2;
+ }
+
+ //check for charcount (maxchars) :)
+ if(char_per_account != 0){
+ sprintf(tmp_sql, "SELECT `account_id` FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if(sql_res){
+ //ok
+ temp = (int)mysql_num_rows(sql_res);
+ if(temp >= char_per_account){
+ //hehe .. limit exceeded :P
+ ShowInfo("Create char failed (%d): charlimit exceeded.\n", sd->account_id);
+ mysql_free_result(sql_res);
+ return -2;
+ }
+ mysql_free_result(sql_res);
+ }
+ }
+
+ // Check Authorised letters/symbols in the name of the character
+ if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+ for (i = 0; i < NAME_LENGTH && name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL)
+ return -2;
+ } else if (char_name_option == 2) { // 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;
+ } // else, all letters/symbols are authorised (except control char removed before)
+
+ //check stat error
+ if ((dat[24]+dat[25]+dat[26]+dat[27]+dat[28]+dat[29]!=6*5 ) || // stats
+ (dat[30] >= 9) || // slots (dat[30] can not be negativ)
+ (dat[33] <= 0) || (dat[33] >= 24) || // hair style
+ (dat[31] >= 9)) { // hair color (dat[31] can not be negativ)
+ if (log_char) {
+ // char.log to charlog
+ sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
+ //query
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
+ return -2;
+ } // for now we have checked: stat points used <31, char slot is less then 9, hair style/color values are acceptable
+
+ // check individual stat value
+ for(i = 24; i <= 29; i++) {
+ if (dat[i] < 1 || dat[i] > 9) {
+ if (log_char) {
+ // char.log to charlog
+ sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
+ //query
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
+ return -2;
+ }
+ } // now we know that every stat has proper value but we have to check if str/int agi/luk vit/dex pairs are correct
+
+ if( ((dat[24]+dat[27]) > 10) || ((dat[25]+dat[29]) > 10) || ((dat[26]+dat[28]) > 10) ) {
+ if (log_char) {
+ // char.log to charlog
+ sprintf(tmp_sql,"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 error", sd->account_id, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
+ //query
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ ShowWarning("Create char failed (%d): stats error (bot cheat?!)\n", sd->account_id);
+ return -2;
+ } // now when we have passed all stat checks
+
+ if (log_char) {
+ // char.log to charlog
+ sprintf(tmp_sql,"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, dat[30], t_name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
+ //query
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ //printf("make new char %d-%d %s %d, %d, %d, %d, %d, %d - %d, %d" RETCODE,
+ // fd, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[33], dat[31]);
+
+ //Check Name (already in use?)
+ sprintf(tmp_sql, "SELECT 1 FROM `%s` WHERE `name` = '%s'",char_db, t_name);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return -2;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if(sql_res){
+ temp = (int)mysql_num_rows(sql_res);
+ mysql_free_result(sql_res);
+ if (temp > 0) {
+ ShowInfo("Create char failed: charname already in use\n");
+ return -1;
+ }
+ }
+
+ // check char slot.
+ sprintf(tmp_sql, "SELECT `account_id`, `char_num` FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d'",char_db, sd->account_id, dat[30]);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if(sql_res){
+ temp = (int)mysql_num_rows(sql_res);
+ mysql_free_result(sql_res);
+ if (temp > 0) {
+ ShowWarning("Create char failed (%d, slot: %d), slot already in use\n", sd->account_id, dat[30]);
+ return -2;
+ }
+ }
+
+ //New Querys [Sirius]
+ //Insert the char to the 'chardb' ^^
+ sprintf(tmp_sql, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
+ "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
+ "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
+ char_db, sd->account_id , dat[30] , t_name, start_zeny, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29],
+ (40 * (100 + dat[26])/100) , (40 * (100 + dat[26])/100 ), (11 * (100 + dat[27])/100), (11 * (100 + dat[27])/100), dat[33], dat[31],
+ mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return -2; //No, stop the procedure!
+ }
+ //Now we need the charid from sql!
+ if(mysql_field_count(&mysql_handle) == 0 &&
+ mysql_insert_id(&mysql_handle) > 0)
+ char_id = (int)mysql_insert_id(&mysql_handle);
+ else {
+ //delete the char ..(no trash in DB!) but how is this possible?
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' AND `name` = '%s'", char_db, sd->account_id, dat[30], t_name);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return -2; //XD end of the (World? :P) .. charcreate (denied)
+ }
+ //Give the char the default items
+ //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`)
+ if (start_weapon > 0) { //add Start Weapon (Knife?)
+ sprintf(tmp_sql,"INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon,1,0x02,1);
+ if (mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ if (start_armor > 0) { //Add default armor (cotton shirt?)
+ sprintf(tmp_sql,"INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `equip`, `identify`) VALUES ('%d', '%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor,1,0x10,1);
+ if (mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, dat[30], name);
+ return char_id;
+}
+
+/*----------------------------------------------------------------------------------------------------------*/
+/* Delete char - davidsiaw */
+/*----------------------------------------------------------------------------------------------------------*/
+/* Returns 0 if successful
+ * Returns < 0 for error
+ */
+int delete_char_sql(int char_id, int partner_id)
+{
+ char char_name[NAME_LENGTH], t_name[NAME_LENGTH*2]; //Name needs be escaped.
+ int account_id=0, party_id=0, guild_id=0, char_base_level=0;
+
+ sprintf(tmp_sql, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level` FROM `%s` WHERE `char_id`='%d'",char_db, char_id);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if(sql_res)
+ sql_row = mysql_fetch_row(sql_res);
+
+ if (sql_res == NULL || sql_row == NULL)
+ {
+ ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n");
+ if (sql_res)
+ mysql_free_result(sql_res);
+ return -1;
+ }
+ strncpy(char_name, sql_row[0], NAME_LENGTH);
+ char_name[NAME_LENGTH-1] = '\0';
+ jstrescapecpy(t_name, char_name); //Escape string for sql use... [Skotlex]
+ account_id = atoi(sql_row[1]);
+ party_id = atoi(sql_row[2]);
+ guild_id = atoi(sql_row[3]);
+ char_base_level = atoi(sql_row[4]);
+ mysql_free_result(sql_res); //Let's free this as soon as possible to avoid problems later on.
+
+ //check for config char del condition [Lupus]
+ if( ( char_del_level > 0 && char_base_level >= char_del_level )
+ || ( char_del_level < 0 && char_base_level <= -char_del_level )
+ ) {
+ ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n",char_name,char_base_level);
+ return -1;
+ }
+
+ /* Divorce [Wizputer] */
+ if (partner_id) {
+ sprintf(tmp_sql,"UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d'",char_db,partner_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND `char_id`='%d'",inventory_db,WEDDING_RING_M,WEDDING_RING_F,partner_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ //Make the character leave the party [Skotlex]
+ if (party_id)
+ inter_party_leave(party_id, account_id, char_id);
+
+ /* delete char's pet */
+ //Delete the hatched pet if you have one...
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'",pet_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ // Komurka's suggested way to clear pets, modified by [Skotlex] (because I always personalize what I do :X)
+ //Removing pets that are in the char's inventory....
+ { //NOTE: The syntax for multi-table deletes is a bit changed between 4.0 and 4.1 regarding aliases, so we have to consider the version... [Skotlex]
+ //Since we only care about the major and minor version, a double conversion is good enough. (4.1.20 -> 4.10000)
+ double mysql_version = atof(mysql_get_server_info(&mysql_handle));
+
+ sprintf(tmp_sql,
+ "delete FROM `%s` USING `%s` as c LEFT JOIN `%s` as i ON c.char_id = i.char_id, `%s` as p WHERE c.char_id = '%d' AND i.card0 = -256 AND p.pet_id = (i.card1|(i.card2<<2))",
+ (mysql_version<4.1?pet_db:"p"), char_db, inventory_db, pet_db, char_id);
+
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ //Removing pets that are in the char's cart....
+ sprintf(tmp_sql,
+ "delete FROM `%s` USING `%s` as c LEFT JOIN `%s` as i ON c.char_id = i.char_id, `%s` as p WHERE c.char_id = '%d' AND i.card0 = -256 AND p.pet_id = (i.card1|(i.card2<<2))",
+ (mysql_version<4.1?pet_db:"p"), char_db, cart_db, pet_db, char_id);
+
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ /* delete char's friends list */
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id` = '%d'",friend_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete char from other's friend list */
+ //NOTE: Won't this cause problems for people who are already online? [Skotlex]
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `friend_id` = '%d'",friend_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete inventory */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",inventory_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete cart inventory */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",cart_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete memo areas */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",memo_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete character registry */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* delete skills */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",skill_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+#ifdef ENABLE_SC_SAVING
+ /* status changes */
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
+ scdata_db, account_id, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+#endif
+
+ if (log_char) {
+ sprintf(tmp_sql,"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, t_name);
+ //query
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ /* delete character */
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",char_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ /* No need as we used inter_guild_leave [Skotlex]
+ // Also delete info from guildtables.
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `char_id`='%d'",guild_member_db, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ */
+
+ sprintf(tmp_sql, "SELECT `guild_id` FROM `%s` WHERE `master` = '%s'", guild_db, t_name);
+
+ if (mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ } else {
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res == NULL) {
+ if (mysql_errno(&mysql_handle) != 0)
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return -1;
+ } else {
+ int rows = (int)mysql_num_rows(sql_res);
+ mysql_free_result(sql_res);
+ if (rows > 0) {
+ mapif_parse_BreakGuild(0,guild_id);
+ }
+ else if (guild_id) //Leave your guild.
+ inter_guild_leave(guild_id, account_id, char_id);
+ }
+ }
+ return 0;
+}
+
+//==========================================================================================================
+
+int count_users(void) {
+ int i, users;
+
+ if (login_fd > 0 && session[login_fd]){
+ users = 0;
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if (server_fd[i] > 0) {
+ users += server[i].users;
+ }
+ }
+ return users;
+ }
+ return 0;
+}
+
+int mmo_char_send006b(int fd, struct char_session_data *sd) {
+ int i, j, found_num = 0;
+ struct mmo_charstatus *p = NULL;
+ const int offset = 24;
+ WFIFOHEAD(fd, offset +9*106);
+
+ set_char_online(-1, 99,sd->account_id);
+
+ //search char.
+ sprintf(tmp_sql, "SELECT `char_id` FROM `%s` WHERE `account_id` = '%d'",char_db, sd->account_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ found_num = (int)mysql_num_rows(sql_res);
+// ShowInfo("number of chars: %d\n", found_num);
+ i = 0;
+ while((sql_row = mysql_fetch_row(sql_res))) {
+ sd->found_char[i] = atoi(sql_row[0]);
+ i++;
+ }
+ mysql_free_result(sql_res);
+ }
+
+ for(i = found_num; i < 9; i++)
+ sd->found_char[i] = -1;
+
+ memset(WFIFOP(fd, 0), 0, offset + found_num * 106);
+ WFIFOW(fd, 0) = 0x6b;
+ WFIFOW(fd, 2) = offset + found_num * 106;
+
+ if (save_log)
+ ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
+
+ for(i = 0; i < found_num; i++) {
+ mmo_char_fromsql_short(sd->found_char[i], &char_dat);
+
+ p = &char_dat;
+
+ j = offset + (i * 106); // increase speed of code
+
+ WFIFOL(fd,j) = p->char_id;
+ WFIFOL(fd,j+4) = p->base_exp>LONG_MAX?LONG_MAX:p->base_exp;
+ WFIFOL(fd,j+8) = p->zeny;
+ WFIFOL(fd,j+12) = p->job_exp>LONG_MAX?LONG_MAX:p->job_exp;
+ WFIFOL(fd,j+16) = p->job_level;
+
+ WFIFOL(fd,j+20) = 0;
+ WFIFOL(fd,j+24) = 0;
+ WFIFOL(fd,j+28) = p->option;
+
+ WFIFOL(fd,j+32) = p->karma;
+ WFIFOL(fd,j+36) = p->manner;
+
+ WFIFOW(fd,j+40) = (p->status_point > SHRT_MAX) ? SHRT_MAX : p->status_point;
+ WFIFOW(fd,j+42) = (p->hp > SHRT_MAX) ? SHRT_MAX : p->hp;
+ WFIFOW(fd,j+44) = (p->max_hp > SHRT_MAX) ? SHRT_MAX : p->max_hp;
+ WFIFOW(fd,j+46) = (p->sp > SHRT_MAX) ? SHRT_MAX : p->sp;
+ WFIFOW(fd,j+48) = (p->max_sp > SHRT_MAX) ? SHRT_MAX : p->max_sp;
+ WFIFOW(fd,j+50) = DEFAULT_WALK_SPEED; // p->speed;
+ WFIFOW(fd,j+52) = p->class_;
+ WFIFOW(fd,j+54) = p->hair;
+ WFIFOW(fd,j+56) = p->option&0x20?0:p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
+ WFIFOW(fd,j+58) = p->base_level;
+ WFIFOW(fd,j+60) = (p->skill_point > SHRT_MAX) ? SHRT_MAX : p->skill_point;
+ WFIFOW(fd,j+62) = p->head_bottom;
+ WFIFOW(fd,j+64) = p->shield;
+ WFIFOW(fd,j+66) = p->head_top;
+ WFIFOW(fd,j+68) = p->head_mid;
+ WFIFOW(fd,j+70) = p->hair_color;
+ WFIFOW(fd,j+72) = p->clothes_color;
+
+ memcpy(WFIFOP(fd,j+74), p->name, NAME_LENGTH);
+
+ WFIFOB(fd,j+98) = (p->str > UCHAR_MAX) ? UCHAR_MAX : p->str;
+ WFIFOB(fd,j+99) = (p->agi > UCHAR_MAX) ? UCHAR_MAX : p->agi;
+ WFIFOB(fd,j+100) = (p->vit > UCHAR_MAX) ? UCHAR_MAX : p->vit;
+ WFIFOB(fd,j+101) = (p->int_ > UCHAR_MAX) ? UCHAR_MAX : p->int_;
+ WFIFOB(fd,j+102) = (p->dex > UCHAR_MAX) ? UCHAR_MAX : p->dex;
+ WFIFOB(fd,j+103) = (p->luk > UCHAR_MAX) ? UCHAR_MAX : p->luk;
+ WFIFOB(fd,j+104) = p->char_num;
+ }
+
+ WFIFOSET(fd,WFIFOW(fd,2));
+// printf("mmo_char_send006b end..\n");
+ return 0;
+}
+
+int send_accounts_tologin(int tid, unsigned int tick, int id, int data);
+
+int parse_tologin(int fd) {
+ int i;
+ struct char_session_data *sd;
+ RFIFOHEAD(fd);
+ // only login-server can have an access to here.
+ // so, if it isn't the login-server, we disconnect the session.
+ //session eof check!
+ if(fd != login_fd)
+ session[fd]->eof = 1;
+ if(session[fd]->eof) {
+ if (fd == login_fd) {
+ ShowWarning("Connection to login-server lost (connection #%d).\n", fd);
+ login_fd = -1;
+ }
+ do_close(fd);
+ return 0;
+ }
+
+ sd = (struct char_session_data*)session[fd]->session_data;
+
+ // hehe. no need to set user limit on SQL version. :P
+ // but char limitation is good way to maintain server. :D
+ while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
+// printf("parse_tologin : %d %d %x\n", fd, RFIFOREST(fd), RFIFOW(fd, 0));
+
+ switch(RFIFOW(fd, 0)){
+ case 0x2711:
+ if (RFIFOREST(fd) < 3)
+ return 0;
+ if (RFIFOB(fd, 2)) {
+ //printf("connect login server error : %d\n", RFIFOB(fd, 2));
+ ShowError("Can not connect to login-server.\n");
+ ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
+ ShowError("Also, please make sure your login db has the correct coounication username/passwords and the gender of the account is S.\n");
+ ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
+ return 0;
+ //exit(1); //fixed for server shutdown.
+ }else {
+ ShowStatus("Connected to login-server (connection #%d).\n", fd);
+
+ //Send online accounts to login server.
+ send_accounts_tologin(-1, gettick(), 0, 0);
+
+ // if no map-server already connected, display a message...
+ for(i = 0; i < MAX_MAP_SERVERS; i++)
+ if (server_fd[i] > 0 && server[i].map[0]) // if map-server online and at least 1 map
+ break;
+ if (i == MAX_MAP_SERVERS)
+ ShowStatus("Awaiting maps from map-server.\n");
+ }
+ RFIFOSKIP(fd, 3);
+ break;
+
+ case 0x2713:
+ if(RFIFOREST(fd)<51)
+ return 0;
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2)) {
+ WFIFOHEAD(i,3);
+ if (RFIFOB(fd,6) != 0) {
+ WFIFOW(i,0) = 0x6c;
+ WFIFOB(i,2) = 0x42;
+ WFIFOSET(i,3);
+ } else if (max_connect_user == 0 || count_users() < max_connect_user) {
+// if (max_connect_user == 0)
+// printf("max_connect_user (unlimited) -> accepted.\n");
+// else
+// printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user);
+ sd->connect_until_time = (time_t)RFIFOL(fd,47);
+ memcpy(sd->email, RFIFOP(fd, 7), 40);
+ // send characters to player
+ mmo_char_send006b(i, sd);
+ } else if(isGM(sd->account_id) >= gm_allow_level) {
+ sd->connect_until_time = (time_t)RFIFOL(fd,47);
+ memcpy(sd->email, RFIFOP(fd, 7), 40);
+ // send characters to player
+ mmo_char_send006b(i, sd);
+ } else {
+ // refuse connection: too much online players
+// printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user);
+ WFIFOW(i,0) = 0x6c;
+ WFIFOW(i,2) = 0;
+ WFIFOSET(i,3);
+ }
+ }
+ }
+ RFIFOSKIP(fd,51);
+ break;
+
+ case 0x2717:
+ if (RFIFOREST(fd) < 50)
+ return 0;
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
+ if (sd->account_id == RFIFOL(fd,2)) {
+ memcpy(sd->email, RFIFOP(fd, 6), 40);
+ sd->connect_until_time = (time_t)RFIFOL(fd,46);
+ break;
+ }
+ }
+ }
+ RFIFOSKIP(fd,50);
+ break;
+
+ // login-server alive packet
+ case 0x2718:
+ if (RFIFOREST(fd) < 2)
+ return 0;
+ RFIFOSKIP(fd,2);
+ break;
+
+ // Receiving authentification from Freya-type login server (to avoid char->login->char)
+ case 0x2719:
+ if (RFIFOREST(fd) < 18)
+ return 0;
+ // to conserv a maximum of authentification, search if account is already authentified and replace it
+ // that will reduce multiple connection too
+ for(i = 0; i < AUTH_FIFO_SIZE; i++)
+ if (auth_fifo[i].account_id == RFIFOL(fd,2))
+ break;
+ // if not found, use next value
+ if (i == AUTH_FIFO_SIZE) {
+ if (auth_fifo_pos >= AUTH_FIFO_SIZE)
+ auth_fifo_pos = 0;
+ i = auth_fifo_pos;
+ auth_fifo_pos++;
+ }
+ //printf("auth_fifo set (auth #%d) - account: %d, secure: %08x-%08x\n", i, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10));
+ auth_fifo[i].account_id = RFIFOL(fd,2);
+ auth_fifo[i].char_id = 0;
+ auth_fifo[i].login_id1 = RFIFOL(fd,6);
+ auth_fifo[i].login_id2 = RFIFOL(fd,10);
+ auth_fifo[i].delflag = 2; // 0: auth_fifo canceled/void, 2: auth_fifo received from login/map server in memory, 1: connection authentified
+ auth_fifo[i].char_pos = 0;
+ auth_fifo[i].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
+ auth_fifo[i].ip = RFIFOL(fd,14);
+ //auth_fifo[i].map_auth = 0;
+ RFIFOSKIP(fd,18);
+ break;
+
+ case 0x2721: // gm reply. I don't want to support this function.
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ RFIFOSKIP(fd, 10);
+/* Note that this is the code from char-txt! Even uncommenting it will not work.
+ printf("0x2721:GM reply\n");
+ {
+ int oldacc, newacc;
+ unsigned char buf[64];
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ oldacc = RFIFOL(fd, 2);
+ newacc = RFIFOL(fd, 6);
+ RFIFOSKIP(fd, 10);
+ if (newacc > 0) {
+ for(i=0;i<char_num;i++){
+ if(char_dat[i].account_id==oldacc)
+ char_dat[i].account_id=newacc;
+ }
+ }
+ WBUFW(buf,0)=0x2b0b;
+ WBUFL(buf,2)=oldacc;
+ WBUFL(buf,6)=newacc;
+ mapif_sendall(buf,10);
+// printf("char -> map\n");
+ }
+*/
+ break;
+ case 0x2723: // changesex reply (modified by [Yor])
+ if (RFIFOREST(fd) < 7)
+ return 0;
+ {
+ int acc, sex;
+ unsigned char buf[16];
+ MYSQL_RES* sql_res2;
+ acc = RFIFOL(fd,2);
+ sex = RFIFOB(fd,6);
+ RFIFOSKIP(fd, 7);
+ if (acc > 0) {
+ sprintf(tmp_sql, "SELECT `char_id`,`class`,`skill_point`,`guild_id` FROM `%s` WHERE `account_id` = '%d'",char_db, acc);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res2 = mysql_store_result(&mysql_handle);
+
+ while(sql_res2 && (sql_row = mysql_fetch_row(sql_res2))) {
+ int char_id, guild_id, jobclass, skill_point, class_;
+ char_id = atoi(sql_row[0]);
+ jobclass = atoi(sql_row[1]);
+ skill_point = atoi(sql_row[2]);
+ guild_id = atoi(sql_row[3]);
+ class_ = jobclass;
+ if (jobclass == JOB_BARD || jobclass == JOB_DANCER ||
+ jobclass == JOB_CLOWN || jobclass == JOB_GYPSY ||
+ jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
+ // job modification
+ if (jobclass == JOB_BARD || jobclass == JOB_DANCER) {
+ class_ = (sex) ? JOB_BARD : JOB_DANCER;
+ } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) {
+ class_ = (sex) ? JOB_CLOWN : JOB_GYPSY;
+ } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
+ class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER;
+ }
+ // remove specifical skills of classes 19,20 4020,4021 and 4042,4043
+ sprintf(tmp_sql, "SELECT `lv` FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'",skill_db, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ while(( sql_row = mysql_fetch_row(sql_res))) {
+ skill_point += atoi(sql_row[0]);
+ }
+ mysql_free_result(sql_res);
+ }
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'",skill_db, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ // to avoid any problem with equipment and invalid sex, equipment is unequiped.
+ sprintf(tmp_sql, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'",inventory_db, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql, "UPDATE `%s` SET `class`='%d' , `skill_point`='%d' , `weapon`='0' , `shield`='0' , `head_top`='0' , `head_mid`='0' , `head_bottom`='0' WHERE `char_id` = '%d'",char_db, class_, skill_point, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ if (guild_id) //If there is a guild, update the guild_member data [Skotlex]
+ inter_guild_sex_changed(guild_id, acc, char_id, sex);
+ }
+ if (sql_res2)
+ mysql_free_result(sql_res2);
+ }
+ // disconnect player if online on char-server
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
+ if (sd->account_id == acc) {
+ session[i]->eof = 1;
+ break;
+ }
+ }
+ }
+
+ WBUFW(buf,0) = 0x2b0d;
+ WBUFL(buf,2) = acc;
+ WBUFB(buf,6) = sex;
+
+ mapif_sendall(buf, 7);
+ }
+ break;
+
+ // account_reg2•ΟX’Κ’m
+ case 0x2729:
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ { //Receive account_reg2 registry, forward to map servers.
+ unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16];
+ memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
+// WBUFW(buf,0) = 0x2b11;
+ 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));
+ RFIFOSKIP(fd, RFIFOW(fd,2));
+ }
+ break;
+
+ // State change of account/ban notification (from login-server) by [Yor]
+ case 0x2731:
+ if (RFIFOREST(fd) < 11)
+ return 0;
+ // send to all map-servers to disconnect the player
+ {
+ unsigned char buf[16];
+ WBUFW(buf,0) = 0x2b14;
+ WBUFL(buf,2) = RFIFOL(fd,2);
+ WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
+ WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
+ mapif_sendall(buf, 11);
+ }
+ // disconnect player if online on char-server
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
+ if (sd->account_id == RFIFOL(fd,2)) {
+ session[i]->eof = 1;
+ break;
+ }
+ }
+ }
+ RFIFOSKIP(fd,11);
+ break;
+
+ case 0x2732:
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ if(!char_gm_read) {
+ unsigned char buf[32000];
+ if (gm_account != NULL)
+ aFree(gm_account);
+ gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * ((RFIFOW(fd,2) - 4) / 5), 1);
+ GM_num = 0;
+ for (i = 4; i < RFIFOW(fd,2); i = i + 5) {
+ gm_account[GM_num].account_id = RFIFOL(fd,i);
+ gm_account[GM_num].level = (int)RFIFOB(fd,i+4);
+ //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
+ GM_num++;
+ }
+ ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num);
+ // send new gm acccounts level to map-servers
+ memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
+ WBUFW(buf,0) = 0x2b15;
+ mapif_sendall(buf, RFIFOW(fd,2));
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ break;
+
+ // Receive GM accounts [Freya login server packet by Yor]
+ case 0x2733:
+ // add test here to remember that the login-server is Freya-type
+ // sprintf (login_server_type, "Freya");
+ if (RFIFOREST(fd) < 7)
+ return 0;
+ {
+ int new_level = 0;
+ for(i = 0; i < GM_num; i++)
+ if (gm_account[i].account_id == RFIFOL(fd,2)) {
+ if (gm_account[i].level != (int)RFIFOB(fd,6)) {
+ gm_account[i].level = (int)RFIFOB(fd,6);
+ new_level = 1;
+ }
+ break;
+ }
+ // if not found, add it
+ if (i == GM_num) {
+ // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???)
+ // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows)
+ if (((int)RFIFOB(fd,6)) > 0 && GM_num < 4000) {
+ if (GM_num == 0) {
+ gm_account = (struct gm_account*)aMalloc(sizeof(struct gm_account));
+ } else {
+ gm_account = (struct gm_account*)aRealloc(gm_account, sizeof(struct gm_account) * (GM_num + 1));
+ }
+ gm_account[GM_num].account_id = RFIFOL(fd,2);
+ gm_account[GM_num].level = (int)RFIFOB(fd,6);
+ new_level = 1;
+ GM_num++;
+ if (GM_num >= 4000)
+ ShowWarning("4000 GM accounts found. Next GM accounts are not readed.\n");
+ }
+ }
+ if (new_level == 1) {
+ ShowStatus("From login-server: receiving GM account information (%d: level %d).\n", RFIFOL(fd,2), (int)RFIFOB(fd,6));
+ mapif_send_gmaccounts();
+
+ //create_online_files(); // not change online file for only 1 player (in next timer, that will be done
+ // send gm acccounts level to map-servers
+ }
+ }
+ RFIFOSKIP(fd,7);
+ break;
+
+ //Login server request to kick a character out. [Skotlex]
+ case 0x2734:
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ {
+ struct online_char_data* character;
+ int aid = RFIFOL(fd,2);
+ if ((character = idb_get(online_char_db, aid)) != NULL)
+ { //Kick out this player.
+ if (character->server > -1)
+ { //Kick it from the map server it is on.
+ mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
+ if (!character->waiting_disconnect)
+ add_timer(gettick()+15000, chardb_waiting_disconnect, character->account_id, 0);
+ character->waiting_disconnect = 1;
+ } else { //Manual kick from char server.
+ struct char_session_data *tsd;
+ int i;
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid)
+ {
+ WFIFOHEAD(i,3);
+ WFIFOW(i,0) = 0x81;
+ WFIFOB(i,2) = 2;
+ WFIFOSET(i,3);
+ break;
+ }
+ }
+ if (i == fd_max) //Shouldn't happen, but just in case.
+ set_char_offline(99, aid);
+ }
+ }
+ RFIFOSKIP(fd,6);
+ }
+ break;
+
+ case 0x2735:
+ {
+ unsigned char buf[2];
+ in_addr_t new_ip = 0;
+ RFIFOSKIP(fd,2);
+
+ WBUFW(buf,0) = 0x2b1e;
+ mapif_sendall(buf, 2);
+
+ new_ip = resolve_hostbyname(login_ip_str, NULL, NULL);
+ if (new_ip && new_ip != login_ip) //Update login ip, too.
+ login_ip = new_ip;
+
+ new_ip = resolve_hostbyname(char_ip_str, NULL, NULL);
+ if (new_ip && new_ip != char_ip)
+ { //Update ip.
+ char_ip = new_ip;
+ ShowInfo("Updating IP for [%s].\n",char_ip_str);
+ WFIFOHEAD(fd,6);
+ WFIFOW(fd,0) = 0x2736;
+ WFIFOL(fd,2) = char_ip;
+ WFIFOSET(fd,6);
+ }
+ break;
+ }
+ default:
+ ShowError("Unknown packet 0x%04x from login server, disconnecting.\n", RFIFOW(fd, 0));
+ session[fd]->eof = 1;
+ return 0;
+ }
+ }
+
+ RFIFOFLUSH(fd);
+
+ return 0;
+}
+
+int request_accreg2(int account_id, int char_id) {
+ if (login_fd > 0) {
+ WFIFOHEAD(login_fd, 10);
+ WFIFOW(login_fd, 0) = 0x272e;
+ WFIFOL(login_fd, 2) = account_id;
+ WFIFOL(login_fd, 6) = char_id;
+ WFIFOSET(login_fd, 10);
+ return 1;
+ }
+ 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;
+ }
+ return 0;
+}
+
+void char_read_fame_list(void)
+{
+ int i;
+ struct fame_list fame_item;
+
+ // Empty ranking lists
+ memset(smith_fame_list, 0, sizeof(smith_fame_list));
+ memset(chemist_fame_list, 0, sizeof(chemist_fame_list));
+ memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list));
+ // Build Blacksmith ranking list
+ sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, fame_list_size_smith);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ i = 0;
+ while((sql_row = mysql_fetch_row(sql_res))) {
+ fame_item.id = atoi(sql_row[0]);
+ fame_item.fame = atoi(sql_row[1]);
+ strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
+ memcpy(&smith_fame_list[i], &fame_item, sizeof(struct fame_list));
+
+ if (++i == fame_list_size_smith)
+ break;
+ }
+ mysql_free_result(sql_res);
+ }
+ // Build Alchemist ranking list
+ sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, fame_list_size_chemist);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ i = 0;
+ while((sql_row = mysql_fetch_row(sql_res))) {
+ fame_item.id = atoi(sql_row[0]);
+ fame_item.fame = atoi(sql_row[1]);
+ strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
+
+ memcpy(&chemist_fame_list[i], &fame_item, sizeof(struct fame_list));
+
+ if (++i == fame_list_size_chemist)
+ break;
+ }
+ mysql_free_result(sql_res);
+ }
+ // Build Taekwon ranking list
+ sprintf(tmp_sql, "SELECT `char_id`,`fame`, `name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ i = 0;
+ while((sql_row = mysql_fetch_row(sql_res))) {
+ fame_item.id = atoi(sql_row[0]);
+ fame_item.fame = atoi(sql_row[1]);
+ strncpy(fame_item.name, sql_row[2], NAME_LENGTH);
+
+ memcpy(&taekwon_fame_list[i], &fame_item, sizeof(struct fame_list));
+
+ if (++i == fame_list_size_taekwon)
+ break;
+ }
+ mysql_free_result(sql_res);
+ }
+}
+
+// Send map-servers the fame ranking lists
+int char_send_fame_list(int fd) {
+ int i, len = 8;
+ unsigned char buf[32000];
+
+ WBUFW(buf,0) = 0x2b1b;
+
+ for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) {
+ memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list));
+ len += sizeof(struct fame_list);
+ }
+ // add blacksmith's block length
+ WBUFW(buf, 6) = len;
+
+ for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) {
+ memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list));
+ len += sizeof(struct fame_list);
+ }
+ // add alchemist's block length
+ WBUFW(buf, 4) = len;
+
+ for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) {
+ memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list));
+ len += sizeof(struct fame_list);
+ }
+ // add total packet length
+ WBUFW(buf, 2) = len;
+
+ if (fd != -1)
+ mapif_send(fd, buf, len);
+ else
+ mapif_sendall(buf, len);
+ return 0;
+}
+
+int search_mapserver(unsigned short map, long ip, short port);
+
+//Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size)
+//Returns 1 on found, 0 on not found (buffer is filled with Unknown char name)
+int char_loadName(int char_id, char* name)
+{
+ sprintf(tmp_sql, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
+
+ if (sql_row)
+ memcpy(name, sql_row[0], NAME_LENGTH);
+ else
+ memcpy(name, unknown_char_name, NAME_LENGTH);
+ if (sql_res) mysql_free_result(sql_res);
+ return sql_row?1:0;
+}
+
+
+int parse_frommap(int fd) {
+ int i = 0, j = 0;
+ int id;
+ RFIFOHEAD(fd);
+
+ // Sometimes fd=0, and it will cause server crash. Don't know why. :(
+ if (fd <= 0) {
+ ShowError("parse_frommap error fd=%d\n", fd);
+ return 0;
+ }
+
+ for(id = 0; id < MAX_MAP_SERVERS; id++)
+ if (server_fd[id] == fd)
+ break;
+ if(id == MAX_MAP_SERVERS)
+ session[fd]->eof = 1;
+ if(session[fd]->eof) {
+ if (id < MAX_MAP_SERVERS) {
+ unsigned char buf[16384];
+ ShowStatus("Map-server %d (session #%d) has disconnected.\n", id, fd);
+ //Notify other map servers that this one is gone. [Skotlex]
+ WBUFW(buf,0) = 0x2b20;
+ WBUFL(buf,4) = server[id].ip;
+ WBUFW(buf,8) = server[id].port;
+ j = 0;
+ for(i = 0; i < MAX_MAP_PER_SERVER; i++)
+ if (server[id].map[i])
+ WBUFW(buf,10+(j++)*4) = server[id].map[i];
+ if (j > 0) {
+ WBUFW(buf,2) = j * 4 + 10;
+ mapif_sendallwos(fd, buf, WBUFW(buf,2));
+ }
+ memset(&server[id], 0, sizeof(struct mmo_map_server));
+ sprintf(tmp_sql, "DELETE FROM `ragsrvinfo` WHERE `index`='%d'", server_fd[id]);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ server_fd[id] = -1;
+ online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
+ }
+ do_close(fd);
+ return 0;
+ }
+
+ while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
+ switch(RFIFOW(fd, 0)) {
+
+ // map-server alive packet
+ case 0x2718:
+ RFIFOSKIP(fd,2);
+ break;
+
+ case 0x2af7:
+ RFIFOSKIP(fd,2);
+ if(char_gm_read) //Re-read gm accounts.
+ read_gm_account();
+ //Send to login request to reload gm accounts.
+ else if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 2);
+ WFIFOW(login_fd,0) = 0x2709;
+ WFIFOSET(login_fd, 2);
+ }
+ break;
+
+ // mapserver -> map names recv.
+ case 0x2afa:
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+ unsigned char *p = (unsigned char *)&server[id].ip;
+ unsigned char buf[16384];
+ int x;
+ WFIFOHEAD(fd,3+NAME_LENGTH);
+
+ memset(server[id].map, 0, sizeof(server[id].map));
+ j = 0;
+ for(i = 4; i < RFIFOW(fd,2); i += 4) {
+ server[id].map[j] = RFIFOW(fd,i);
+ j++;
+ }
+
+ ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
+ id, j, p[0], p[1], p[2], p[3], server[id].port);
+ ShowStatus("Map-server %d loading complete.\n", id);
+
+ if (max_account_id != DEFAULT_MAX_ACCOUNT_ID || max_char_id != DEFAULT_MAX_CHAR_ID)
+ mapif_send_maxid(max_account_id, max_char_id); //Send the current max ids to the server to keep in sync [Skotlex]
+
+ WFIFOW(fd,0) = 0x2afb;
+ WFIFOB(fd,2) = 0;
+ // name for wisp to player
+ memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH);
+ WFIFOSET(fd,3+NAME_LENGTH);
+
+ char_send_fame_list(fd); //Send fame list.
+
+ if (j == 0)
+ ShowWarning("Map-Server %d have NO maps.\n", id);
+ else {
+ // Transmitting maps information to the other map-servers
+ WBUFW(buf,0) = 0x2b04;
+ WBUFW(buf,2) = j * 4 + 10;
+ WBUFL(buf,4) = server[id].ip;
+ WBUFW(buf,8) = server[id].port;
+ memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
+ mapif_sendallwos(fd, buf, WBUFW(buf,2));
+ }
+ // Transmitting the maps of the other map-servers to the new map-server
+ for(x = 0; x < MAX_MAP_SERVERS; x++) {
+ if (server_fd[x] > 0 && x != id) {
+ WFIFOHEAD(fd, 10 +4*MAX_MAP_PER_SERVER);
+ WFIFOW(fd,0) = 0x2b04;
+ WFIFOL(fd,4) = server[x].ip;
+ WFIFOW(fd,8) = server[x].port;
+ j = 0;
+ for(i = 0; i < MAX_MAP_PER_SERVER; i++)
+ if (server[x].map[i])
+ WFIFOW(fd,10+(j++)*4) = server[x].map[i];
+ if (j > 0) {
+ WFIFOW(fd,2) = j * 4 + 10;
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ }
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ }
+ break;
+ //Packet command is now used for sc_data request. [Skotlex]
+ case 0x2afc:
+ if (RFIFOREST(fd) < 10)
+ return 0;
+ {
+ int aid, cid;
+ aid = RFIFOL(fd,2);
+ cid = RFIFOL(fd,6);
+ RFIFOSKIP(fd, 10);
+#ifdef ENABLE_SC_SAVING
+ sprintf(tmp_sql, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
+ scdata_db, aid, cid);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ break;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ struct status_change_data data;
+ int count = 0;
+ WFIFOHEAD(fd, 14+50*sizeof(struct status_change_data));
+ WFIFOW(fd, 0) = 0x2b1d;
+ WFIFOL(fd, 4) = aid;
+ WFIFOL(fd, 8) = cid;
+ while((sql_row = mysql_fetch_row(sql_res)) && count < 50)
+ {
+ data.type = atoi(sql_row[0]);
+ data.tick = atoi(sql_row[1]);
+ data.val1 = atoi(sql_row[2]);
+ data.val2 = atoi(sql_row[3]);
+ data.val3 = atoi(sql_row[4]);
+ data.val4 = atoi(sql_row[5]);
+ memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &data, sizeof(struct status_change_data));
+ count++;
+ }
+ if (count >= 50)
+ ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
+ mysql_free_result(sql_res);
+ if (count > 0)
+ {
+ WFIFOW(fd, 2) = 14 + count*sizeof(struct status_change_data);
+ WFIFOW(fd, 12) = count;
+ WFIFOSET(fd, WFIFOW(fd,2));
+
+ //Clear the data once loaded.
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+#endif
+ break;
+ }
+ //set MAP user count
+ case 0x2afe:
+ if (RFIFOREST(fd) < 4)
+ return 0;
+ if (RFIFOW(fd,2) != server[id].users) {
+ server[id].users = RFIFOW(fd,2);
+ ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
+ }
+ RFIFOSKIP(fd, 4);
+ break;
+ // set MAP user
+ case 0x2aff:
+ if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+ //TODO: When data mismatches memory, update guild/party online/offline states.
+ int i, aid, cid;
+ struct online_char_data* character;
+
+ online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
+ server[id].users = RFIFOW(fd,4);
+ for(i = 0; i < server[id].users; i++) {
+ aid = RFIFOL(fd,6+i*8);
+ cid = RFIFOL(fd,6+i*8+4);
+ character = idb_ensure(online_char_db, aid, create_online_char_data);
+ if (character->server > -1 && character->server != id)
+ {
+ ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
+ character->account_id, character->char_id, character->server, id, aid, cid);
+ mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
+ }
+ character->server = id;
+ character->char_id = cid;
+ }
+ //If any chars remain in -2, they will be cleaned in the cleanup timer.
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ break;
+ }
+ // char saving
+ case 0x2b01:
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+ 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));
+ RFIFOSKIP(fd,size);
+ break;
+ }
+ //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
+ if (RFIFOB(fd,12) || (
+ (character = idb_get(online_char_db, aid)) != NULL &&
+ character->char_id == cid))
+ {
+ 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);
+ set_char_online(id, cid, aid);
+ }
+
+ if (RFIFOB(fd,12))
+ { //Flag? Set character offline after saving [Skotlex]
+ set_char_offline(cid, aid);
+ WFIFOHEAD(fd, 10);
+ WFIFOW(fd, 0) = 0x2b21; //Save ack only needed on final save.
+ WFIFOL(fd, 2) = aid;
+ WFIFOL(fd, 6) = cid;
+ WFIFOSET(fd, 10);
+ }
+ RFIFOSKIP(fd,size);
+ break;
+ }
+ // req char selection
+ case 0x2b02:
+ if (RFIFOREST(fd) < 18)
+ return 0;
+
+ if (auth_fifo_pos >= AUTH_FIFO_SIZE)
+ auth_fifo_pos = 0;
+
+ auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd, 2);
+ auth_fifo[auth_fifo_pos].char_id = 0;
+ auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd, 6);
+ auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10);
+ auth_fifo[auth_fifo_pos].delflag = 2;
+ auth_fifo[auth_fifo_pos].char_pos = 0;
+ auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
+ auth_fifo[auth_fifo_pos].ip = RFIFOL(fd,14);
+ auth_fifo_pos++;
+ {
+ WFIFOHEAD(fd, 7);
+ WFIFOW(fd, 0) = 0x2b03;
+ WFIFOL(fd, 2) = RFIFOL(fd, 2);
+ WFIFOB(fd, 6) = 0;
+ WFIFOSET(fd, 7);
+ }
+ RFIFOSKIP(fd, 18);
+ break;
+
+ // request "change map server"
+ case 0x2b05:
+ if (RFIFOREST(fd) < 35)
+ return 0;
+ {
+ unsigned short name;
+ int map_id, map_fd = -1;
+ struct online_char_data* data;
+ struct mmo_charstatus* char_data;
+ name = RFIFOW(fd,18);
+ map_id = search_mapserver(name, RFIFOL(fd,24), RFIFOW(fd,28)); //Locate mapserver by ip and port.
+ if (map_id >= 0)
+ map_fd = server_fd[map_id];
+ //Char should just had been saved before this packet, so this should be safe. [Skotlex]
+ char_data = uidb_get(char_db_,RFIFOL(fd,14));
+ if (char_data == NULL)
+ { //Really shouldn't happen.
+ mmo_char_fromsql(RFIFOL(fd,14), &char_dat);
+ char_data = &char_dat;
+ }
+ //Tell the new map server about this player using Kevin's new auth packet. [Skotlex]
+ if (map_fd>=0 && session[map_fd] && char_data)
+ { //Send the map server the auth of this player.
+ //Update the "last map" as this is where the player must be spawned on the new map server.
+ WFIFOHEAD(fd, 30);
+ WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
+ char_data->last_point.map = RFIFOW(fd,18);
+ char_data->last_point.x = RFIFOW(fd,20);
+ char_data->last_point.y = RFIFOW(fd,22);
+ char_data->sex = RFIFOB(fd,30); // Buuyo^
+
+ WFIFOW(map_fd,0) = 0x2afd;
+ WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
+ WFIFOL(map_fd,4) = RFIFOL(fd, 2); //Account ID
+ WFIFOL(map_fd,8) = RFIFOL(fd, 6); //Login1
+ WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2
+ WFIFOL(map_fd,12) = (unsigned long)0; //TODO: connect_until_time, how do I figure it out right now?
+ memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus));
+ WFIFOSET(map_fd, WFIFOW(map_fd,2));
+ data = idb_ensure(online_char_db, RFIFOL(fd, 2), create_online_char_data);
+ data->char_id = char_data->char_id;
+ data->server = map_id; //Update server where char is.
+
+ //Reply with an ack.
+ WFIFOW(fd, 0) = 0x2b06;
+ memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
+ WFIFOSET(fd, 30);
+ } else { //Reply with nak
+ WFIFOHEAD(fd, 30);
+ WFIFOW(fd, 0) = 0x2b06;
+ memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
+ WFIFOL(fd, 6) = 0; //Set login1 to 0.
+ WFIFOSET(fd, 30);
+ }
+ RFIFOSKIP(fd, 35);
+ }
+ break;
+
+ // char name check
+ case 0x2b08:
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ {
+ char name[NAME_LENGTH];
+ WFIFOHEAD(fd,30);
+ char_loadName((int)RFIFOL(fd,2), name);
+ WFIFOW(fd,0) = 0x2b09;
+ WFIFOL(fd,2) = RFIFOL(fd,2);
+ memcpy(WFIFOP(fd,6), name, NAME_LENGTH);
+ WFIFOSET(fd,30);
+ RFIFOSKIP(fd,6);
+ }
+ break;
+
+ // I want become GM - fuck!
+ case 0x2b0a:
+ if(RFIFOREST(fd)<4)
+ return 0;
+ if(RFIFOREST(fd)<RFIFOW(fd,2))
+ return 0;
+ /*
+ memcpy(WFIFOP(login_fd,2),RFIFOP(fd,2),RFIFOW(fd,2)-2);
+ WFIFOW(login_fd,0)=0x2720;
+ WFIFOSET(login_fd,RFIFOW(fd,2));
+// printf("char : change gm -> login %d %s %d\n", RFIFOL(fd, 4), RFIFOP(fd, 8), RFIFOW(fd, 2));
+ */
+ ShowWarning("packet 0x2ba (become GM) is not supported by the Char-Server.\n");
+ RFIFOSKIP(fd, RFIFOW(fd, 2));
+ break;
+
+ // Map server send information to change an email of an account -> login-server
+ case 0x2b0c:
+ if (RFIFOREST(fd) < 86)
+ return 0;
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 86);
+ memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0), 86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
+ WFIFOW(login_fd,0) = 0x2722;
+ WFIFOSET(login_fd, 86);
+ }
+ RFIFOSKIP(fd, 86);
+ break;
+
+ // Receiving from map-server a status change resquest. Transmission to login-server (by Yor)
+ case 0x2b0e:
+ if (RFIFOREST(fd) < 44)
+ return 0;
+ {
+ char character_name[NAME_LENGTH], t_name[NAME_LENGTH*2];
+ int acc = RFIFOL(fd,2); // account_id of who ask (-1 if nobody)
+ WFIFOHEAD(fd, 34);
+ memcpy(character_name, RFIFOP(fd,6), NAME_LENGTH);
+ character_name[NAME_LENGTH-1] = '\0';
+ jstrescapecpy(t_name, character_name); //Escape string for sql use... [Skotlex]
+ // prepare answer
+ WFIFOW(fd,0) = 0x2b0f; // answer
+ WFIFOL(fd,2) = acc; // who want do operation
+ WFIFOW(fd,30) = RFIFOW(fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
+ sprintf(tmp_sql, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'",char_db, t_name);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ if (mysql_num_rows(sql_res)) {
+ sql_row = mysql_fetch_row(sql_res);
+ memcpy(WFIFOP(fd,6), sql_row[1], NAME_LENGTH); // put correct name if found
+ WFIFOW(fd,32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ switch(RFIFOW(fd, 30)) {
+ case 1: // block
+ if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = atoi(sql_row[0]); // account value
+ WFIFOL(login_fd,6) = 5; // status of the account
+ WFIFOSET(login_fd, 10);
+ } else
+ WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ } else
+ WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ break;
+ case 2: // ban
+ if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 18);
+ WFIFOW(login_fd, 0) = 0x2725;
+ WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
+ WFIFOW(login_fd, 6) = RFIFOW(fd,32); // year
+ WFIFOW(login_fd, 8) = RFIFOW(fd,34); // month
+ WFIFOW(login_fd,10) = RFIFOW(fd,36); // day
+ WFIFOW(login_fd,12) = RFIFOW(fd,38); // hour
+ WFIFOW(login_fd,14) = RFIFOW(fd,40); // minute
+ WFIFOW(login_fd,16) = RFIFOW(fd,42); // second
+ WFIFOSET(login_fd,18);
+ } else
+ WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ } else
+ WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ break;
+ case 3: // unblock
+ if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = atoi(sql_row[0]); // account value
+ WFIFOL(login_fd,6) = 0; // status of the account
+ WFIFOSET(login_fd, 10);
+ } else
+ WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ } else
+ WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ break;
+ case 4: // unban
+ if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 6);
+ WFIFOW(login_fd, 0) = 0x272a;
+ WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
+ WFIFOSET(login_fd, 6);
+ } else
+ WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ } else
+ WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ break;
+ case 5: // changesex
+ if (acc == -1 || isGM(acc) >= isGM(atoi(sql_row[0]))) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd, 6);
+ WFIFOW(login_fd, 0) = 0x2727;
+ WFIFOL(login_fd, 2) = atoi(sql_row[0]); // account value
+ WFIFOSET(login_fd, 6);
+ } else
+ WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ } else
+ WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ break;
+ }
+ } else {
+ // character name not found
+ memcpy(WFIFOP(fd,6), character_name, NAME_LENGTH);
+ WFIFOW(fd,32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
+ }
+ // send answer if a player ask, not if the server ask
+ if (acc != -1) {
+ WFIFOSET(fd, 34);
+ }
+ mysql_free_result(sql_res);
+ }
+ }
+ RFIFOSKIP(fd, 44);
+ break;
+
+// case 0x2b0f: Not used anymore, available for future use
+
+ // Update and send fame ranking list [DracoRPG]
+ case 0x2b10:
+ if (RFIFOREST(fd) < 12)
+ return 0;
+ {
+ int cid = RFIFOL(fd, 2);
+ int fame = RFIFOL(fd, 6);
+ char type = RFIFOB(fd, 10);
+ char pos = RFIFOB(fd, 11);
+ int size = 0;
+ struct fame_list *list = NULL;
+ RFIFOSKIP(fd,12);
+
+ 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;
+ }
+ if(!size) break; //No list.
+ if(pos)
+ {
+ pos--; //Convert from pos to index.
+ if(
+ (pos == 0 || fame < list[pos-1].fame) &&
+ (pos == size-1 || fame > list[pos+1].fame)
+ ) { //No change in order.
+ list[(int)pos].fame = fame;
+ char_send_fame_list(fd);
+ break;
+ }
+ // If the player's already in the list, remove the entry and shift the following ones 1 step up
+ memmove(list+pos, list+pos+1, (size-pos-1) * sizeof(struct fame_list));
+ //Clear out last entry.
+ list[size-1].id = 0;
+ list[size-1].fame = 0;
+ }
+
+ // Find the position where the player has to be inserted
+ for(i = 0; i < size && fame < list[i].fame; i++);
+ if(i>=size) break; //Out of ranking.
+ // When found someone with less or as much fame, insert just above
+ memmove(list+i+1, list+i, (size-i-1) * sizeof(struct fame_list));
+ list[i].id = cid;
+ list[i].fame = fame;
+ // Look for the player's name
+ char_loadName(list[i].id, list[i].name);
+ char_send_fame_list(-1);
+ }
+
+ break;
+
+ // Receive rates [Wizputer]
+ case 0x2b16:
+ if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
+ return 0;
+ {
+ char motd[256], t_name[512]; //Required for jstrescapecpy [Skotlex]
+ strncpy(motd, RFIFOP(fd,10), 255); //First copy it to make sure the motd fits.
+ motd[255]='\0';
+ jstrescapecpy(t_name,motd);
+
+ sprintf(tmp_sql, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d',`motd`='%s'",
+ fd, server_name, RFIFOW(fd,2), RFIFOW(fd,4), RFIFOW(fd,6), t_name);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ RFIFOSKIP(fd,RFIFOW(fd,8));
+ break;
+ }
+
+ // Character disconnected set online 0 [Wizputer]
+ case 0x2b17:
+ if (RFIFOREST(fd) < 6 )
+ return 0;
+ //printf("Setting %d char offline\n",RFIFOL(fd,2));
+ set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
+ RFIFOSKIP(fd,10);
+ break;
+ // Reset all chars to offline [Wizputer]
+ case 0x2b18:
+ set_all_offline(id);
+ RFIFOSKIP(fd,2);
+ break;
+ // Character set online [Wizputer]
+ case 0x2b19:
+ if (RFIFOREST(fd) < 6 )
+ return 0;
+ set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
+ RFIFOSKIP(fd,10);
+ break;
+
+ // Build and send fame ranking lists [DracoRPG]
+ case 0x2b1a:
+ if (RFIFOREST(fd) < 2)
+ return 0;
+ char_read_fame_list();
+ char_send_fame_list(-1);
+ RFIFOSKIP(fd,2);
+ break;
+
+ //Request saving sc_data of a player. [Skotlex]
+ case 0x2b1c:
+ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
+ return 0;
+ {
+#ifdef ENABLE_SC_SAVING
+ int count, aid, cid, i;
+ struct status_change_data data;
+ char *p = tmp_sql;
+
+ aid = RFIFOL(fd, 4);
+ cid = RFIFOL(fd, 8);
+ count = RFIFOW(fd, 12);
+
+ p+= sprintf(p, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
+
+ for (i = 0; i < count; i++)
+ {
+ memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
+ p += sprintf (p, " ('%d','%d','%hu','%d','%d','%d','%d','%d'),", aid, cid,
+ data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
+ }
+ if (count > 0)
+ {
+ *--p = '\0'; //Remove final comma.
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+#endif
+ RFIFOSKIP(fd, RFIFOW(fd, 2));
+ break;
+ }
+
+ case 0x2736:
+ if (RFIFOREST(fd) < 6) return 0;
+ ShowInfo("Updated IP address of Server #%d to %d.%d.%d.%d.\n",id,
+ (int)RFIFOB(fd,2),(int)RFIFOB(fd,3),
+ (int)RFIFOB(fd,4),(int)RFIFOB(fd,5));
+ server[id].ip = RFIFOL(fd, 2);
+ RFIFOSKIP(fd,6);
+ break;
+
+ default:
+ // inter server - packet
+ {
+ int r = inter_parse_frommap(fd);
+ if (r == 1) break; // processed
+ if (r == 2) return 0; // need more packet
+ }
+
+ // no inter server packet. no char server packet -> disconnect
+ ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
+ session[fd]->eof = 1;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int search_mapserver(unsigned short map, long ip, short port) {
+ int i, j;
+
+ if (!map)
+ return -1;
+
+ for(i = 0; i < MAX_MAP_SERVERS; i++)
+ if (server_fd[i] > 0)
+ for (j = 0; server[i].map[j]; j++)
+ if (server[i].map[j] == map) {
+ if (ip > 0 && server[i].ip != ip)
+ continue;
+ if (port > 0 && server[i].port != port)
+ continue;
+ return i;
+ }
+
+ return -1;
+}
+
+int char_mapif_init(int fd) {
+ return inter_mapif_init(fd);
+}
+
+//--------------------------------------------
+// Test to know if an IP come from LAN or WAN.
+// Rewrote: Adnvanced subnet check [LuzZza]
+//--------------------------------------------
+int lan_subnetcheck(long *p) {
+
+ int i;
+ unsigned char *sbn, *msk, *src = (unsigned char *)p;
+
+ for(i=0; i<subnet_count; i++) {
+
+ if((subnet[i].subnet & subnet[i].mask) == (*p & subnet[i].mask)) {
+
+ sbn = (unsigned char *)&subnet[i].subnet;
+ msk = (unsigned char *)&subnet[i].mask;
+
+ ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n",
+ src[0], src[1], src[2], src[3], sbn[0], sbn[1], sbn[2], sbn[3], msk[0], msk[1], msk[2], msk[3]);
+
+ return subnet[i].map_ip;
+ }
+ }
+
+ ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", src[0], src[1], src[2], src[3]);
+ return 0;
+}
+
+int parse_char(int fd) {
+
+ int i, ch = 0;
+ char email[40];
+ unsigned char buf[64];
+ unsigned short cmd;
+ int map_fd;
+ struct char_session_data *sd;
+ unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr;
+ long subnet_map_ip;
+ RFIFOHEAD(fd);
+
+ sd = (struct char_session_data*)session[fd]->session_data;
+
+ if(login_fd < 0)
+ session[fd]->eof = 1;
+ if(session[fd]->eof) {
+ if (fd == login_fd)
+ login_fd = -1;
+ if (sd != NULL)
+ {
+ struct online_char_data* data = idb_get(online_char_db, sd->account_id);
+ if (!data || data->server== -1) //If it is not in any server, send it offline. [Skotlex]
+ set_char_offline(99,sd->account_id);
+ }
+ do_close(fd);
+ return 0;
+ }
+
+ while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
+ cmd = RFIFOW(fd,0);
+ // crc32‚ΜƒXƒLƒbƒv—p
+ if( sd==NULL && // –’ƒƒOƒCƒ“orŠΗ—ƒpƒPƒbƒg
+ RFIFOREST(fd)>=4 && // Ε’αƒoƒCƒg”§Œΐ • 0x7530,0x7532ŠΗ—ƒpƒPœ‹Ž
+ RFIFOREST(fd)<=21 && // Ε‘εƒoƒCƒg”§Œΐ • ƒT[ƒo[ƒƒOƒCƒ“œ‹Ž
+ cmd!=0x20b && // md5’Κ’mƒpƒPƒbƒgœ‹Ž
+ (RFIFOREST(fd)<6 || RFIFOW(fd,4)==0x65) ){ // ŽŸ‚Ι‰½‚©ƒpƒPƒbƒg‚ͺ—ˆ‚Δ‚ι‚Θ‚ηAΪ‘±‚Ε‚Θ‚’‚Ζ‚Ύ‚ί
+ RFIFOSKIP(fd,4);
+ cmd = RFIFOW(fd,0);
+ ShowDebug("parse_char : %d crc32 skipped\n",fd);
+ if(RFIFOREST(fd)==0)
+ return 0;
+ }
+
+//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) { RFIFOSKIP(fd,rest); return 0; } }
+
+ switch(cmd){
+ case 0x20b: //20040622 encryption ragexe correspondence
+ if (RFIFOREST(fd) < 19)
+ return 0;
+ RFIFOSKIP(fd,19);
+ break;
+
+ case 0x65: // request to connect
+ ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10));
+ if (RFIFOREST(fd) < 17)
+ return 0;
+ {
+ WFIFOHEAD(fd, 4);
+
+ if (sd) {
+ //Received again auth packet for already authentified account?? Discard it.
+ //TODO: Perhaps log this as a hack attempt?
+ RFIFOSKIP(fd,17);
+ break;
+ }
+ CREATE(session[fd]->session_data, struct char_session_data, 1);
+ sd = (struct char_session_data*)session[fd]->session_data;
+ sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server)
+ sd->account_id = RFIFOL(fd, 2);
+ sd->login_id1 = RFIFOL(fd, 6);
+ sd->login_id2 = RFIFOL(fd, 10);
+ sd->sex = RFIFOB(fd, 16);
+
+ WFIFOL(fd, 0) = RFIFOL(fd, 2);
+ WFIFOSET(fd, 4);
+
+ for(i = 0; i < AUTH_FIFO_SIZE; i++) {
+ if (auth_fifo[i].account_id == sd->account_id &&
+ auth_fifo[i].login_id1 == sd->login_id1 &&
+#if CMP_AUTHFIFO_LOGIN2 != 0
+ auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18
+#endif
+ (!check_ip_flag || auth_fifo[i].ip == session[fd]->client_addr.sin_addr.s_addr) &&
+ auth_fifo[i].delflag == 2) {
+ auth_fifo[i].delflag = 1;
+
+ if (online_check)
+ { // check if character is not online already. [Skotlex]
+ struct online_char_data* character;
+ character = idb_get(online_char_db, sd->account_id);
+
+ if (character)
+ {
+ if (character->server > -1)
+ { //Character already online. KICK KICK KICK
+ mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
+ if (!character->waiting_disconnect)
+ add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
+ character->waiting_disconnect = 1;
+ /* Not a good idea because this would trigger when you do a char-change from the map server! [Skotlex]
+ } else { //Kick from char server.
+ struct char_session_data *tsd;
+ int i;
+ for(i = 0; i < fd_max; i++) {
+ if (session[i] && i != fd && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == sd->account_id)
+ {
+ WFIFOW(i,0) = 0x81;
+ WFIFOB(i,2) = 2;
+ WFIFOSET(i,3);
+ break;
+ }
+ if (i == fd_max) //Shouldn't happen, but just in case.
+ set_char_offline(99, sd->account_id);
+ }
+ */
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 8;
+ WFIFOSET(fd,3);
+ break;
+ }
+ }
+ }
+
+ if (max_connect_user == 0 || count_users() < max_connect_user) {
+ if (login_fd > 0) { // don't send request if no login-server
+ // request to login-server to obtain e-mail/time limit
+ WFIFOHEAD(login_fd, 6);
+ WFIFOW(login_fd,0) = 0x2716;
+ WFIFOL(login_fd,2) = sd->account_id;
+ WFIFOSET(login_fd,6);
+ }
+ // send characters to player
+ mmo_char_send006b(fd, sd);
+ } else {
+ // refuse connection (over populated)
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOW(fd,2) = 0;
+ WFIFOSET(fd,3);
+ }
+// printf("connection request> set delflag 1(o:2)- account_id:%d/login_id1:%d(fifo_id:%d)\n", sd->account_id, sd->login_id1, i);
+ break;
+ }
+ }
+ if (i == AUTH_FIFO_SIZE) {
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd,19);
+ WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
+ WFIFOL(login_fd,2) = sd->account_id;
+ WFIFOL(login_fd,6) = sd->login_id1;
+ WFIFOL(login_fd,10) = sd->login_id2;
+ WFIFOB(login_fd,14) = sd->sex;
+ WFIFOL(login_fd,15) = session[fd]->client_addr.sin_addr.s_addr;
+ WFIFOSET(login_fd,19);
+ } else { // if no login-server, we must refuse connection
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ }
+ }
+ }
+ RFIFOSKIP(fd, 17);
+ break;
+
+ case 0x66: // char select
+ FIFOSD_CHECK(3);
+
+ sprintf(tmp_sql, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'",char_db, sd->account_id, RFIFOB(fd, 2));
+ RFIFOSKIP(fd, 3);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
+
+ if (sql_row)
+ {
+ int char_id = atoi(sql_row[0]);
+ mysql_free_result(sql_res); //Free'd as soon as possible
+ mmo_char_fromsql(char_id, &char_dat);
+ char_dat.sex = sd->sex;
+ } else {
+ mysql_free_result(sql_res);
+ break;
+ }
+
+ if (log_char) {
+ char escaped_name[NAME_LENGTH*2];
+ sprintf(tmp_sql,"INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
+ charlog_db, sd->account_id, RFIFOB(fd, 2), jstrescapecpy(escaped_name, char_dat.name));
+ //query
+ if(mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ ShowInfo("Selected char: (Account %d: %d - %s)" RETCODE, sd->account_id, RFIFOB(fd, 2), char_dat.name);
+
+ i = search_mapserver(char_dat.last_point.map, -1, -1);
+
+ // if map is not found, we check major cities
+ if (i < 0) {
+ unsigned short j;
+ //First check that there's actually a map server online.
+ for(j = 0; j < MAX_MAP_SERVERS; j++)
+ if (server_fd[j] >= 0 && server[j].map[0])
+ break;
+ if (j == MAX_MAP_SERVERS) {
+ ShowInfo("Connection Closed. No map servers available.\n");
+ WFIFOHEAD(fd, 3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ break;
+ }
+ if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 273;
+ char_dat.last_point.y = 354;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 120;
+ char_dat.last_point.y = 100;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 160;
+ char_dat.last_point.y = 94;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 116;
+ char_dat.last_point.y = 57;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 87;
+ char_dat.last_point.y = 117;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
+ char_dat.last_point.x = 94;
+ char_dat.last_point.y = 103;
+ } else {
+ ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(char_dat.last_point.map));
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ break;
+ }
+ ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(char_dat.last_point.map), mapindex_id2name(j));
+ char_dat.last_point.map = j;
+ }
+ { //Send player to map.
+ WFIFOHEAD(fd,28);
+ WFIFOW(fd, 0) =0x71;
+ WFIFOL(fd, 2) =char_dat.char_id;
+ memcpy(WFIFOP(fd,6), mapindex_id2name(char_dat.last_point.map), MAP_NAME_LENGTH);
+
+ // Advanced subnet check [LuzZza]
+ if((subnet_map_ip = lan_subnetcheck((long *)p)))
+ WFIFOL(fd,22) = subnet_map_ip;
+ else
+ WFIFOL(fd,22) = server[i].ip;
+
+ WFIFOW(fd,26) = server[i].port;
+ WFIFOSET(fd,28);
+ }
+ if (auth_fifo_pos >= AUTH_FIFO_SIZE) {
+ auth_fifo_pos = 0;
+ }
+ auth_fifo[auth_fifo_pos].account_id = sd->account_id;
+ auth_fifo[auth_fifo_pos].char_id = char_dat.char_id;
+ auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1;
+ auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2;
+ auth_fifo[auth_fifo_pos].delflag = 0;
+ auth_fifo[auth_fifo_pos].char_pos = 0;
+ auth_fifo[auth_fifo_pos].sex = sd->sex;
+ auth_fifo[auth_fifo_pos].connect_until_time = sd->connect_until_time;
+ auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr.sin_addr.s_addr;
+
+ //Send NEW auth packet [Kevin]
+ if ((map_fd = server_fd[i]) < 1 || session[map_fd] == NULL)
+ {
+ ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
+ server_fd[i] = -1;
+ memset(&server[i], 0, sizeof(struct mmo_map_server));
+ break;
+ }
+ { //Send auth ok to map server
+ WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus));
+ WFIFOW(map_fd,0) = 0x2afd;
+ WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
+ WFIFOL(map_fd,4) = auth_fifo[auth_fifo_pos].account_id;
+ WFIFOL(map_fd,8) = auth_fifo[auth_fifo_pos].login_id1;
+ WFIFOL(map_fd,16) = auth_fifo[auth_fifo_pos].login_id2;
+ WFIFOL(map_fd,12) = (unsigned long)auth_fifo[auth_fifo_pos].connect_until_time;
+ memcpy(WFIFOP(map_fd,20), &char_dat, sizeof(struct mmo_charstatus));
+ WFIFOSET(map_fd, WFIFOW(map_fd,2));
+ }
+
+ set_char_online(i, auth_fifo[auth_fifo_pos].char_id, auth_fifo[auth_fifo_pos].account_id);
+ //Checks to see if the even share setting of the party must be broken.
+ inter_party_logged(char_dat.party_id, char_dat.account_id, char_dat.char_id);
+ auth_fifo_pos++;
+ break;
+
+ case 0x67: // make new
+ FIFOSD_CHECK(37);
+
+ if(char_new == 0) //turn character creation on/off [Kevin]
+ i = -2;
+ else
+ i = make_new_char_sql(fd, RFIFOP(fd, 2));
+
+ //'Charname already exists' (-1), 'Char creation denied' (-2)
+ //And 'You are underaged' (-3) (XD) [Sirius]
+ if (i < 0)
+ {
+ WFIFOHEAD(fd, 3);
+ WFIFOW(fd, 0) = 0x6e;
+ switch (i) {
+ case -1: WFIFOB(fd, 2) = 0x00; break;
+ case -2: WFIFOB(fd, 2) = 0x02; break;
+ case -3: WFIFOB(fd, 2) = 0x01; break;
+ }
+ WFIFOSET(fd, 3);
+ RFIFOSKIP(fd, 37);
+ break;
+ }
+ { //Send data.
+ WFIFOHEAD(fd, 108);
+ WFIFOW(fd, 0) = 0x6d;
+ memset(WFIFOP(fd, 2), 0x00, 106);
+
+ mmo_char_fromsql_short(i, &char_dat); //Only the short data is needed.
+ WFIFOL(fd, 2) = char_dat.char_id;
+ WFIFOL(fd,2+4) = char_dat.base_exp>LONG_MAX?LONG_MAX:char_dat.base_exp;
+ WFIFOL(fd,2+8) = char_dat.zeny;
+ WFIFOL(fd,2+12) = char_dat.job_exp>LONG_MAX?LONG_MAX:char_dat.job_exp;
+ WFIFOL(fd,2+16) = char_dat.job_level;
+
+ WFIFOL(fd,2+28) = char_dat.karma;
+ WFIFOL(fd,2+32) = char_dat.manner;
+
+ WFIFOW(fd,2+40) = 0x30;
+ WFIFOW(fd,2+42) = (char_dat.hp > SHRT_MAX) ? SHRT_MAX : char_dat.hp;
+ WFIFOW(fd,2+44) = (char_dat.max_hp > SHRT_MAX) ? SHRT_MAX : char_dat.max_hp;
+ WFIFOW(fd,2+46) = (char_dat.sp > SHRT_MAX) ? SHRT_MAX : char_dat.sp;
+ WFIFOW(fd,2+48) = (char_dat.max_sp > SHRT_MAX) ? SHRT_MAX : char_dat.max_sp;
+ WFIFOW(fd,2+50) = DEFAULT_WALK_SPEED; // char_dat[i].speed;
+ WFIFOW(fd,2+52) = char_dat.class_;
+ WFIFOW(fd,2+54) = char_dat.hair;
+
+ WFIFOW(fd,2+58) = char_dat.base_level;
+ WFIFOW(fd,2+60) = (char_dat.skill_point > SHRT_MAX) ? SHRT_MAX : char_dat.skill_point;
+
+ WFIFOW(fd,2+64) = char_dat.shield;
+ WFIFOW(fd,2+66) = char_dat.head_top;
+ WFIFOW(fd,2+68) = char_dat.head_mid;
+ WFIFOW(fd,2+70) = char_dat.hair_color;
+
+ memcpy(WFIFOP(fd,2+74), char_dat.name, NAME_LENGTH);
+
+ WFIFOB(fd,2+98) = char_dat.str>UCHAR_MAX?UCHAR_MAX:char_dat.str;
+ WFIFOB(fd,2+99) = char_dat.agi>UCHAR_MAX?UCHAR_MAX:char_dat.agi;
+ WFIFOB(fd,2+100) = char_dat.vit>UCHAR_MAX?UCHAR_MAX:char_dat.vit;
+ WFIFOB(fd,2+101) = char_dat.int_>UCHAR_MAX?UCHAR_MAX:char_dat.int_;
+ WFIFOB(fd,2+102) = char_dat.dex>UCHAR_MAX?UCHAR_MAX:char_dat.dex;
+ WFIFOB(fd,2+103) = char_dat.luk>UCHAR_MAX?UCHAR_MAX:char_dat.luk;
+ WFIFOB(fd,2+104) = char_dat.char_num;
+
+ WFIFOSET(fd, 108);
+ RFIFOSKIP(fd, 37);
+ }
+ //to do
+ for(ch = 0; ch < 9; ch++) {
+ if (sd->found_char[ch] == -1) {
+ sd->found_char[ch] = char_dat.char_id;
+ break;
+ }
+ }
+ break;
+ case 0x68: /* delete char */
+ FIFOSD_CHECK(46);
+ {
+ int cid = RFIFOL(fd,2);
+ WFIFOHEAD(fd, 46);
+ ShowInfo(CL_RED" Request Char Deletion:"CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
+ memcpy(email, RFIFOP(fd,6), 40);
+
+ /* Check if e-mail is correct */
+ if(strcmpi(email, sd->email)){
+ if(strcmp("a@a.com", sd->email) == 0){
+ if(strcmp("a@a.com", email) == 0 || strcmp("", email) == 0){
+ //ignore
+ }else{
+ //del fail
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ RFIFOSKIP(fd, 46);
+ break;
+ }
+ }else{
+ //del fail
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ RFIFOSKIP(fd, 46);
+ break;
+ }
+ }
+
+ for(i = 0; i < 9; i++) {
+ /* Debug:
+ printf("Checking if char to be deleted: %d - %d (%d)\n", sd->found_char[i], RFIFOL(fd, 2), sd->account_id);
+ */
+ if (sd->found_char[i] == cid) {
+ for(ch = i; ch < 9-1; ch++)
+ sd->found_char[ch] = sd->found_char[ch+1];
+ sd->found_char[8] = -1;
+ break;
+ }
+ }
+ /* Such a character does not exist in the account */
+ /* If so, you are so screwed. */
+ if (i == 9) {
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ break;
+ }
+
+ /* Grab the partner id */
+ sprintf(tmp_sql, "SELECT `partner_id` FROM `%s` WHERE `char_id`='%d'",char_db, cid);
+
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if(sql_res)
+ {
+ int char_pid=0;
+ sql_row = mysql_fetch_row(sql_res);
+ if (sql_row)
+ char_pid = atoi(sql_row[0]);
+ mysql_free_result(sql_res);
+
+ /* Delete character and partner (if any) */
+ if(delete_char_sql(cid, char_pid)<0){
+ //can't delete the char
+ //either SQL error or can't delete by some CONFIG conditions
+ //del fail
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ RFIFOSKIP(fd, 46);
+ break;
+ }
+ if (char_pid != 0)
+ { /* If there is partner, tell map server to do divorce */
+ WBUFW(buf,0) = 0x2b12;
+ WBUFL(buf,2) = RFIFOL(fd,2);
+ WBUFL(buf,6) = char_pid;
+ mapif_sendall(buf,10);
+ }
+ }
+ /* Char successfully deleted.*/
+ WFIFOW(fd, 0) = 0x6f;
+ WFIFOSET(fd, 2);
+
+ RFIFOSKIP(fd, 46);
+ break;
+ }
+ case 0x2af8: // login as map-server
+ if (RFIFOREST(fd) < 60)
+ return 0;
+ {
+ char *l_userid = RFIFOP(fd,2);
+ char *l_password = RFIFOP(fd,26);
+ WFIFOHEAD(fd, 4+5*GM_num);
+
+ l_userid[23] = '\0';
+ l_password[23] = '\0';
+ WFIFOW(fd, 0) = 0x2af9;
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if (server_fd[i] <= 0)
+ break;
+ }
+ if (i == MAX_MAP_SERVERS ||
+ strcmp(l_userid, userid) ||
+ strcmp(l_password, passwd)) {
+ WFIFOB(fd,2) = 3;
+ WFIFOSET(fd, 3);
+ } else {
+ int len;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd, 3);
+ session[fd]->func_parse = parse_frommap;
+ server_fd[i] = fd;
+ server[i].ip = RFIFOL(fd, 54);
+ server[i].port = RFIFOW(fd, 58);
+ server[i].users = 0;
+ memset(server[i].map, 0, sizeof(server[i].map));
+ realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+ char_mapif_init(fd);
+ // send gm acccounts level to map-servers
+ len = 4;
+ WFIFOW(fd,0) = 0x2b15;
+ for(i = 0; i < GM_num; i++) {
+ WFIFOL(fd,len) = gm_account[i].account_id;
+ WFIFOB(fd,len+4) = (unsigned char)gm_account[i].level;
+ len += 5;
+ }
+ WFIFOW(fd,2) = len;
+ WFIFOSET(fd,len);
+ }
+ RFIFOSKIP(fd,60);
+ break;
+ }
+ case 0x187: // Alive?
+ if (RFIFOREST(fd) < 6) {
+ return 0;
+ }
+ RFIFOSKIP(fd, 6);
+ break;
+
+ case 0x7530: // Athena info get
+ {
+ WFIFOHEAD(fd, 10);
+ WFIFOW(fd, 0) = 0x7531;
+ WFIFOB(fd, 2) = ATHENA_MAJOR_VERSION;
+ WFIFOB(fd, 3) = ATHENA_MINOR_VERSION;
+ WFIFOB(fd, 4) = ATHENA_REVISION;
+ WFIFOB(fd, 5) = ATHENA_RELEASE_FLAG;
+ WFIFOB(fd, 6) = ATHENA_OFFICIAL_FLAG;
+ WFIFOB(fd, 7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR;
+ WFIFOW(fd, 8) = ATHENA_MOD_VERSION;
+ WFIFOSET(fd, 10);
+ RFIFOSKIP(fd, 2);
+ return 0;
+ }
+ case 0x7532: // disconnect(default also disconnect)
+ default:
+ session[fd]->eof = 1;
+ return 0;
+ }
+ }
+ RFIFOFLUSH(fd);
+
+ return 0;
+}
+
+// Console Command Parser [Wizputer]
+int parse_console(char *buf) {
+ char *type,*command;
+
+ type = (char *)aMalloc(64);
+ command = (char *)aMalloc(64);
+
+ memset(type,0,64);
+ memset(command,0,64);
+
+ ShowNotice("Console: %s\n",buf);
+
+ if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 )
+ sscanf(buf,"%[^\n]",type);
+
+ ShowNotice("Type of command: %s || Command: %s \n",type,command);
+
+ if(buf) aFree(buf);
+ if(type) aFree(type);
+ if(command) aFree(command);
+
+ return 0;
+}
+
+// MAP send all
+int mapif_sendall(unsigned char *buf, unsigned int len) {
+ int i, c;
+ int fd;
+
+ c = 0;
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if ((fd = server_fd[i]) > 0) { //0 Should not be a valid server_fd [Skotlex]
+ WFIFOHEAD(fd,len);
+#if 0 //This seems to have been fixed long long ago.
+ if (session[fd] == NULL)
+ { //Could this be the crash's source? [Skotlex]
+ ShowError("mapif_sendall: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", fd, i);
+ server_fd[i] = -1;
+ memset(&server[i], 0, sizeof(struct mmo_map_server));
+ continue;
+ }
+#endif
+ memcpy(WFIFOP(fd,0), buf, len);
+ WFIFOSET(fd,len);
+ c++;
+ }
+ }
+
+ return c;
+}
+
+int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) {
+ int i, c;
+ int fd;
+
+ c = 0;
+ for(i=0, c=0;i<MAX_MAP_SERVERS;i++){
+ if ((fd = server_fd[i]) > 0 && fd != sfd) {
+ WFIFOHEAD(fd, len);
+ memcpy(WFIFOP(fd,0), buf, len);
+ WFIFOSET(fd, len);
+ c++;
+ }
+ }
+
+ return c;
+}
+
+int mapif_send(int fd, unsigned char *buf, unsigned int len) {
+ int i;
+
+ if (fd >= 0) {
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if (fd == server_fd[i]) {
+ WFIFOHEAD(fd,len);
+ memcpy(WFIFOP(fd,0), buf, len);
+ WFIFOSET(fd,len);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int send_users_tologin(int tid, unsigned int tick, int id, int data) {
+ int users = count_users();
+ unsigned char buf[16];
+
+ if (login_fd > 0 && session[login_fd]) {
+ // send number of user to login server
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x2714;
+ WFIFOL(login_fd,2) = users;
+ WFIFOSET(login_fd,6);
+ }
+ // send number of players to all map-servers
+ WBUFW(buf,0) = 0x2b00;
+ WBUFL(buf,2) = users;
+ mapif_sendall(buf, 6);
+
+ return 0;
+}
+
+static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) {
+ struct online_char_data* character = (struct online_char_data*)data;
+ int *i = va_arg(ap, int*);
+ int count = va_arg(ap, int);
+ if ((*i) >= count)
+ return 0; //This is an error that shouldn't happen....
+ if(character->server > -1) {
+ WFIFOHEAD(login_fd, 8+count*4);
+ WFIFOL(login_fd, 8+(*i)*4) =character->account_id;
+ (*i)++;
+ return 1;
+ }
+ return 0;
+}
+
+int send_accounts_tologin(int tid, unsigned int tick, int id, int data) {
+ int users = count_users(), i=0;
+
+ if (login_fd > 0 && session[login_fd]) {
+ // send account list to login server
+ WFIFOHEAD(login_fd, 8+users*4);
+ WFIFOW(login_fd,0) = 0x272d;
+ WFIFOL(login_fd,4) = users;
+ online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users);
+ WFIFOW(login_fd,2) = 8+ i*4;
+ WFIFOSET(login_fd,WFIFOW(login_fd,2));
+ }
+ return 0;
+}
+
+int check_connect_login_server(int tid, unsigned int tick, int id, int data) {
+ if (login_fd > 0 && session[login_fd] != NULL)
+ return 0;
+
+ ShowInfo("Attempt to connect to login-server...\n");
+ login_fd = make_connection(login_ip, login_port);
+ if (login_fd == -1)
+ { //Try again later. [Skotlex]
+ login_fd = 0;
+ return 0;
+ }
+ session[login_fd]->func_parse = parse_tologin;
+ realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+ {
+ WFIFOHEAD(login_fd, 86);
+ WFIFOW(login_fd,0) = 0x2710;
+ memcpy(WFIFOP(login_fd,2), userid, 24);
+ memcpy(WFIFOP(login_fd,26), passwd, 24);
+ WFIFOL(login_fd,50) = 0;
+ WFIFOL(login_fd,54) = char_ip;
+ WFIFOL(login_fd,58) = char_port;
+ memcpy(WFIFOP(login_fd,60), server_name, 20);
+ WFIFOW(login_fd,80) = 0;
+ WFIFOW(login_fd,82) = char_maintenance;
+ WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
+ WFIFOSET(login_fd,86);
+ }
+ return 0;
+}
+
+//------------------------------------------------
+//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, int data)
+{
+ struct online_char_data* character;
+ if ((character = idb_get(online_char_db, id)) != NULL && character->waiting_disconnect)
+ { //Mark it offline due to timeout.
+ set_char_offline(character->char_id, character->account_id);
+ }
+ return 0;
+}
+
+//----------------------------------------------------------
+// Return numerical value of a switch configuration by [Yor]
+// on/off, english, franηais, deutsch, espaρol
+//----------------------------------------------------------
+int config_switch(const char *str) {
+ if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
+ return 1;
+ if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
+ return 0;
+
+ return atoi(str);
+}
+
+//----------------------------------
+// Reading Lan Support configuration
+// Rewrote: Anvanced subnet check [LuzZza]
+//----------------------------------
+int char_lan_config_read(const char *lancfgName) {
+
+ FILE *fp;
+ int line_num = 0;
+ char line[1024], w1[64], w2[64], w3[64], w4[64];
+
+ if((fp = fopen(lancfgName, "r")) == NULL) {
+ ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
+ return 1;
+ }
+
+ ShowInfo("Reading the configuration file %s...\n", lancfgName);
+
+ while(fgets(line, sizeof(line)-1, fp)) {
+
+ line_num++;
+ if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
+ continue;
+
+ line[sizeof(line)-1] = '\0';
+ if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) {
+
+ ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
+ continue;
+ }
+
+ remove_control_chars((unsigned char *)w1);
+ remove_control_chars((unsigned char *)w2);
+ remove_control_chars((unsigned char *)w3);
+ remove_control_chars((unsigned char *)w4);
+
+ if(strcmpi(w1, "subnet") == 0) {
+
+ subnet[subnet_count].mask = inet_addr(w2);
+ subnet[subnet_count].char_ip = inet_addr(w3);
+ subnet[subnet_count].map_ip = inet_addr(w4);
+ subnet[subnet_count].subnet = subnet[subnet_count].char_ip&subnet[subnet_count].mask;
+ if (subnet[subnet_count].subnet != (subnet[subnet_count].map_ip&subnet[subnet_count].mask)) {
+ ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
+ continue;
+ }
+
+ subnet_count++;
+ }
+
+ ShowStatus("Read information about %d subnetworks.\n", subnet_count);
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+void do_final(void) {
+ ShowInfo("Doing final stage...\n");
+ //inter_save();
+ do_final_itemdb();
+ //check SQL save progress.
+ //wait until save char complete
+
+ set_all_offline(-1);
+ set_all_offline_sql();
+
+ inter_final();
+
+ flush_fifos();
+
+ mapindex_final();
+
+ sprintf(tmp_sql,"DELETE FROM `ragsrvinfo");
+ if (mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ if(gm_account) {
+ aFree(gm_account);
+ gm_account = 0;
+ }
+
+ delete_session(login_fd);
+ delete_session(char_fd);
+ char_db_->destroy(char_db_, NULL);
+ online_char_db->destroy(online_char_db, NULL);
+
+ mysql_close(&mysql_handle);
+ if(char_gm_read)
+ mysql_close(&lmysql_handle);
+
+ ShowInfo("ok! all done...\n");
+}
+#endif //TXT_SQL_CONVERT
+void sql_config_read(const char *cfgName){ /* Kalaspuff, to get login_db */
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ ShowInfo("Reading file %s...\n", cfgName);
+
+ if ((fp = fopen(cfgName, "r")) == NULL) {
+ ShowFatalError("file not found: %s\n", cfgName);
+ exit(1);
+ }
+
+ while(fgets(line, sizeof(line)-1, fp)){
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
+ continue;
+
+ if(strcmpi(w1,"char_db")==0){
+ strcpy(char_db,w2);
+#ifndef TXT_SQL_CONVERT
+ } else if(strcmpi(w1, "gm_read_method") == 0) {
+ if(atoi(w2) != 0)
+ char_gm_read = true;
+ else
+ char_gm_read = false;
+ //custom columns for login database
+ }else if(strcmpi(w1,"login_db")==0){
+ strcpy(login_db, w2);
+ }else if(strcmpi(w1,"login_db_level")==0){
+ strcpy(login_db_level,w2);
+ }else if(strcmpi(w1,"login_db_account_id")==0){
+ strcpy(login_db_account_id,w2);
+ }else if(strcmpi(w1,"lowest_gm_level")==0){
+ lowest_gm_level = atoi(w2);
+ ShowStatus("set lowest_gm_level : %s\n",w2);
+#endif
+ }else if(strcmpi(w1,"scdata_db")==0){
+ strcpy(scdata_db,w2);
+ }else if(strcmpi(w1,"cart_db")==0){
+ strcpy(cart_db,w2);
+ }else if(strcmpi(w1,"inventory_db")==0){
+ strcpy(inventory_db,w2);
+ }else if(strcmpi(w1,"charlog_db")==0){
+ strcpy(charlog_db,w2);
+ }else if(strcmpi(w1,"storage_db")==0){
+ strcpy(storage_db,w2);
+ }else if(strcmpi(w1,"reg_db")==0){
+ strcpy(reg_db,w2);
+ }else if(strcmpi(w1,"skill_db")==0){
+ strcpy(skill_db,w2);
+ }else if(strcmpi(w1,"interlog_db")==0){
+ strcpy(interlog_db,w2);
+ }else if(strcmpi(w1,"memo_db")==0){
+ strcpy(memo_db,w2);
+ }else if(strcmpi(w1,"guild_db")==0){
+ strcpy(guild_db,w2);
+ }else if(strcmpi(w1,"guild_alliance_db")==0){
+ strcpy(guild_alliance_db,w2);
+ }else if(strcmpi(w1,"guild_castle_db")==0){
+ strcpy(guild_castle_db,w2);
+ }else if(strcmpi(w1,"guild_expulsion_db")==0){
+ strcpy(guild_expulsion_db,w2);
+ }else if(strcmpi(w1,"guild_member_db")==0){
+ strcpy(guild_member_db,w2);
+ }else if(strcmpi(w1,"guild_skill_db")==0){
+ strcpy(guild_skill_db,w2);
+ }else if(strcmpi(w1,"guild_position_db")==0){
+ strcpy(guild_position_db,w2);
+ }else if(strcmpi(w1,"guild_storage_db")==0){
+ strcpy(guild_storage_db,w2);
+ }else if(strcmpi(w1,"party_db")==0){
+ strcpy(party_db,w2);
+ }else if(strcmpi(w1,"pet_db")==0){
+ strcpy(pet_db,w2);
+ }else if(strcmpi(w1,"friend_db")==0){
+ strcpy(friend_db,w2);
+#ifndef TXT_SQL_CONVERT
+ }else if(strcmpi(w1,"db_path")==0){
+ strcpy(db_path,w2);
+ //Map server option to use SQL db or not
+ }else if(strcmpi(w1,"use_sql_db")==0){ // added for sql item_db read for char server [Valaris]
+ db_use_sqldbs = config_switch(w2);
+ ShowStatus("Using SQL dbs: %s\n",w2);
+ }else if(strcmpi(w1,"item_db_db")==0){
+ strcpy(item_db_db,w2);
+ }else if(strcmpi(w1,"item_db2_db")==0){
+ strcpy(item_db2_db,w2);
+ } else if(strcmpi(w1,"connection_ping_interval")==0) {
+ connection_ping_interval = config_switch(w2);
+#endif
+ //support the import command, just like any other config
+ }else if(strcmpi(w1,"import")==0){
+ sql_config_read(w2);
+ }
+
+ }
+ fclose(fp);
+ ShowInfo("done reading %s.\n", cfgName);
+}
+#ifndef TXT_SQL_CONVERT
+
+int char_config_read(const char *cfgName) {
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ if ((fp = fopen(cfgName, "r")) == NULL) {
+ ShowFatalError("Configuration file not found: %s.\n", cfgName);
+ exit(1);
+ }
+
+ ShowInfo("Reading file %s...\n", cfgName);
+ while(fgets(line, sizeof(line)-1, fp)) {
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+
+ line[sizeof(line)-1] = '\0';
+ if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2)
+ continue;
+
+ remove_control_chars((unsigned char *) w1);
+ remove_control_chars((unsigned char *) w2);
+ if(strcmpi(w1,"timestamp_format")==0) {
+ strncpy(timestamp_format, w2, 20);
+ } else if(strcmpi(w1,"console_silent")==0){
+ msg_silent = 0; //To always allow the next line to show up.
+ ShowInfo("Console Silent Setting: %d\n", atoi(w2));
+ msg_silent = atoi(w2);
+ } else if(strcmpi(w1,"stdout_with_ansisequence")==0){
+ stdout_with_ansisequence = config_switch(w2);
+ } else if (strcmpi(w1, "userid") == 0) {
+ strncpy(userid, w2, 24);
+ } else if (strcmpi(w1, "passwd") == 0) {
+ strncpy(passwd, w2, 24);
+ } else if (strcmpi(w1, "server_name") == 0) {
+ strncpy(server_name, w2, 20);
+ server_name[sizeof(server_name) - 1] = '\0';
+ ShowStatus("%s server has been initialized\n", w2);
+ } else if (strcmpi(w1, "wisp_server_name") == 0) {
+ if (strlen(w2) >= 4) {
+ memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
+ wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
+ }
+ } else if (strcmpi(w1, "login_ip") == 0) {
+ unsigned char ip_str[16];
+ login_ip = resolve_hostbyname(w2, NULL, ip_str);
+ if (login_ip) {
+ strncpy(login_ip_str, w2, sizeof(login_ip_str));
+ ShowStatus("Login server IP address : %s -> %s\n", w2, ip_str);
+ }
+ } else if (strcmpi(w1, "login_port") == 0) {
+ login_port=atoi(w2);
+ } else if (strcmpi(w1, "char_ip") == 0) {
+ unsigned char ip_str[16];
+ char_ip = resolve_hostbyname(w2, NULL, ip_str);
+ if (char_ip){
+ strncpy(char_ip_str, w2, sizeof(char_ip_str));
+ ShowStatus("Character server IP address : %s -> %s\n", w2, ip_str);
+ }
+ } else if (strcmpi(w1, "bind_ip") == 0) {
+ unsigned char ip_str[16];
+ bind_ip = resolve_hostbyname(w2, NULL, ip_str);
+ if (bind_ip) {
+ strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
+ ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip_str);
+ }
+ } 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_new")==0){
+ char_new = atoi(w2);
+ } else if (strcmpi(w1, "char_new_display")==0){
+ char_new_display = atoi(w2);
+ } else if (strcmpi(w1, "max_connect_user") == 0) {
+ max_connect_user = atoi(w2);
+ if (max_connect_user < 0)
+ max_connect_user = 0; // unlimited online players
+ } else if(strcmpi(w1, "gm_allow_level") == 0) {
+ gm_allow_level = atoi(w2);
+ if(gm_allow_level < 0)
+ gm_allow_level = 99;
+ } else if (strcmpi(w1, "check_ip_flag") == 0) {
+ check_ip_flag = config_switch(w2);
+ } else if (strcmpi(w1, "online_check") == 0) {
+ online_check = config_switch(w2);
+ } else if (strcmpi(w1, "autosave_time") == 0) {
+ autosave_interval = atoi(w2)*1000;
+ if (autosave_interval <= 0)
+ autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
+ } else if (strcmpi(w1, "save_log") == 0) {
+ save_log = config_switch(w2);
+ } else if (strcmpi(w1, "start_point") == 0) {
+ char map[MAP_NAME_LENGTH];
+ int x, y;
+ if (sscanf(w2,"%16[^,],%d,%d", map, &x, &y) < 3)
+ continue;
+ if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
+ 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;
+ start_point.y = y;
+ }
+ } else if (strcmpi(w1, "start_zeny") == 0) {
+ start_zeny = atoi(w2);
+ if (start_zeny < 0)
+ start_zeny = 0;
+ } else if (strcmpi(w1, "start_weapon") == 0) {
+ start_weapon = atoi(w2);
+ if (start_weapon < 0)
+ start_weapon = 0;
+ } else if (strcmpi(w1, "start_armor") == 0) {
+ start_armor = atoi(w2);
+ if (start_armor < 0)
+ start_armor = 0;
+ } else if(strcmpi(w1,"log_char")==0){ //log char or not [devil]
+ log_char = atoi(w2);
+ } else if (strcmpi(w1, "unknown_char_name") == 0) {
+ strcpy(unknown_char_name, w2);
+ unknown_char_name[NAME_LENGTH-1] = 0;
+ } else if (strcmpi(w1, "name_ignoring_case") == 0) {
+ name_ignoring_case = config_switch(w2);
+ } else if (strcmpi(w1, "char_name_option") == 0) {
+ char_name_option = atoi(w2);
+ } else if (strcmpi(w1, "char_name_letters") == 0) {
+ strcpy(char_name_letters, w2);
+ } else if (strcmpi(w1, "check_ip_flag") == 0) {
+ check_ip_flag = config_switch(w2);
+ } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
+ char_per_account = atoi(w2);
+ } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
+ char_del_level = atoi(w2);
+ } else if (strcmpi(w1, "console") == 0) {
+ if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 )
+ console = 1;
+ } else if (strcmpi(w1, "fame_list_alchemist") == 0) {
+ fame_list_size_chemist = atoi(w2);
+ if (fame_list_size_chemist > MAX_FAME_LIST) {
+ ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST);
+ fame_list_size_chemist = MAX_FAME_LIST;
+ }
+ } else if (strcmpi(w1, "fame_list_blacksmith") == 0) {
+ fame_list_size_smith = atoi(w2);
+ if (fame_list_size_smith > MAX_FAME_LIST) {
+ ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST);
+ fame_list_size_smith = MAX_FAME_LIST;
+ }
+ } else if (strcmpi(w1, "fame_list_taekwon") == 0) {
+ fame_list_size_taekwon = atoi(w2);
+ if (fame_list_size_taekwon > MAX_FAME_LIST) {
+ ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST);
+ fame_list_size_taekwon = MAX_FAME_LIST;
+ }
+ } else if (strcmpi(w1, "guild_exp_rate") == 0) {
+ guild_exp_rate = atoi(w2);
+ } else if (strcmpi(w1, "import") == 0) {
+ char_config_read(w2);
+ }
+ }
+ fclose(fp);
+
+ ShowInfo("Done reading %s.\n", cfgName);
+
+ return 0;
+}
+
+void set_server_type(void)
+{
+ SERVER_TYPE = ATHENA_SERVER_CHAR;
+}
+
+static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
+{
+ struct online_char_data *character= (struct online_char_data*)data;
+ if (character->server == -2) //Unknown server.. set them offline
+ set_char_offline(character->char_id, character->account_id);
+ if (character->server < 0)
+ //Free data from players that have not been online for a while.
+ db_remove(online_char_db, key);
+ return 0;
+}
+
+static int online_data_cleanup(int tid, unsigned int tick, int id, int data)
+{
+ online_char_db->foreach(online_char_db, online_data_cleanup_sub);
+ return 0;
+}
+
+int do_init(int argc, char **argv){
+ int i;
+
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ memset(&server[i], 0, sizeof(struct mmo_map_server));
+ server_fd[i] = -1;
+ }
+
+ //Read map indexes
+ mapindex_init();
+ start_point.map = mapindex_name2id("new_zone01.gat");
+
+ 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);
+
+ if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) {
+ ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n");
+ ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n");
+ ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n");
+ }
+
+ ShowInfo("Finished reading the char-server configuration.\n");
+
+ inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server ΓΚ±βΘ­
+ ShowInfo("Finished reading the inter-server configuration.\n");
+
+ //Read ItemDB
+ do_init_itemdb();
+
+ ShowInfo("Initializing char server.\n");
+ online_char_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+ mmo_char_sql_init();
+ ShowInfo("char server initialized.\n");
+
+// ShowDebug("set parser -> parse_char()...\n");
+ set_defaultparse(parse_char);
+
+// ShowDebug("set terminate function -> do_final().....\n");
+
+ if ((naddr_ != 0) && (!login_ip || !char_ip)) {
+ // The char server should know what IP address it is running on
+ // - MouseJstr
+ int localaddr = ntohl(addr_[0]);
+ unsigned char *ptr = (unsigned char *) &localaddr;
+ char buf[16];
+ sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
+ if (naddr_ != 1)
+ ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", buf);
+ else
+ ShowStatus("Defaulting to %s as our IP address\n", buf);
+ if (!login_ip) {
+ strcpy(login_ip_str, buf);
+ login_ip = inet_addr(login_ip_str);
+ }
+ if (!char_ip) {
+ strcpy(char_ip_str, buf);
+ char_ip = inet_addr(char_ip_str);
+ }
+ if (ptr[0] == 192 && ptr[1] == 168)
+ ShowWarning("Firewall detected.. edit subnet_athena.conf and char_athena.conf\n");
+ }
+
+ ShowInfo("open port %d.....\n",char_port);
+ char_fd = make_listen_bind(bind_ip?bind_ip:INADDR_ANY,char_port);
+
+ add_timer_func_list(check_connect_login_server, "check_connect_login_server");
+ add_timer_func_list(send_users_tologin, "send_users_tologin");
+ add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
+ add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
+
+ add_timer_func_list(online_data_cleanup, "online_data_cleanup");
+ add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600 * 1000);
+
+ // send ALIVE PING to login server.
+ add_timer_interval(gettick() + 10, check_connect_login_server, 0, 0, 10 * 1000);
+ // send USER COUNT PING to login server.
+ add_timer_interval(gettick() + 10, send_users_tologin, 0, 0, 5 * 1000);
+ add_timer_interval(gettick() + 3600*1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour.
+
+ char_read_fame_list(); //Read fame lists.
+
+ if(char_gm_read)
+ read_gm_account();
+
+
+ if ( console ) {
+ set_defaultconsoleparse(parse_console);
+ start_console();
+ }
+
+ //Cleaning the tables for NULL entrys @ startup [Sirius]
+ //Chardb clean
+ ShowInfo("Cleaning the '%s' table...\n", char_db);
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `account_id` = '0'", char_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ //guilddb clean
+ ShowInfo("Cleaning the '%s' table...\n", guild_db);
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ //guildmemberdb clean
+ ShowInfo("Cleaning the '%s' table...\n", guild_member_db);
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db);
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ ShowInfo("End of char server initilization function.\n");
+ ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port);
+ return 0;
+}
+
+#undef mysql_query
+
+int debug_mysql_query(char *file, int line, void *mysql, const char *q) {
+#ifdef TWILIGHT
+ ShowDebug("sql: %s:%d# %s\n", file, line, q);
+#endif
+ return mysql_query((MYSQL *) mysql, q);
+}
+
+int char_child(int parent_id, int child_id) {
+ int tmp_id = 0;
+ sprintf (tmp_sql, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id);
+ if (mysql_query (&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result (&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row (sql_res):NULL;
+ if (sql_row)
+ tmp_id = atoi (sql_row[0]);
+ else
+ ShowError("CHAR: child Failed!\n");
+ if (sql_res) mysql_free_result (sql_res);
+ if ( tmp_id == child_id )
+ return 1;
+ else
+ return 0;
+}
+
+int char_married(int pl1,int pl2) {
+ int tmp_id = 0;
+ sprintf (tmp_sql, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1);
+ if (mysql_query (&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result (&mysql_handle);
+ sql_row = sql_res?mysql_fetch_row (sql_res):NULL;
+ if (sql_row)
+ tmp_id = atoi (sql_row[0]);
+ else
+ ShowError("CHAR: married Failed!\n");
+ if (sql_res) mysql_free_result (sql_res);
+ if ( tmp_id == pl2 )
+ return 1;
+ else
+ return 0;
+}
+
+int char_family(int pl1,int pl2,int pl3) {
+ int charid, partnerid, childid;
+ sprintf (tmp_sql, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, pl1, pl2, pl3);
+ if (mysql_query (&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ sql_res = mysql_store_result (&mysql_handle);
+ if (!sql_res) return 0;
+
+ while((sql_row = mysql_fetch_row(sql_res)))
+ {
+ charid = atoi(sql_row[0]);
+ partnerid = atoi(sql_row[1]);
+ childid = atoi(sql_row[2]);
+ if (charid == pl1) {
+ if ((pl2 == partnerid && pl3 == childid) ||
+ (pl3 == partnerid && pl2 == childid)
+ ) {
+ mysql_free_result (sql_res);
+ return childid;
+ }
+ }
+ if(charid == pl2) {
+ if ((pl1 == partnerid && pl3 == childid) ||
+ (pl3 == partnerid && pl1 == childid)
+ ) {
+ mysql_free_result (sql_res);
+ return childid;
+ }
+ }
+ if(charid == pl3) {
+ if ((pl1 == partnerid && pl2 == childid) ||
+ (pl2 == partnerid && pl1 == childid)
+ ) {
+ mysql_free_result (sql_res);
+ return childid;
+ }
+ }
+ }
+ mysql_free_result (sql_res);
+ return 0;
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/char.h b/src/char_sql/char.h
index 70d8e3b13..1ad48fc9b 100644
--- a/src/char_sql/char.h
+++ b/src/char_sql/char.h
@@ -1,110 +1,110 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-#ifndef _CHARSQL_H_
-#define _CHARSQL_H_
-
-#include "../common/core.h"
-#include "../common/socket.h"
-#include "../common/timer.h"
-#include "../common/mmo.h"
-#include "../common/version.h"
-#include "../common/db.h"
-#include "../common/mapindex.h"
-
-#include "inter.h"
-#include "int_pet.h"
-#include "int_guild.h"
-#include "int_party.h"
-#include "int_storage.h"
-#include "itemdb.h"
-
-#define START_CHAR_NUM 150000
-#define MAX_MAP_SERVERS 30
-
-#define LAN_CONF_NAME "conf/subnet_athena.conf"
-
-#define DEFAULT_AUTOSAVE_INTERVAL 300*1000
-
-struct itemtmp {
- int flag;//checked = 1 else 0
- int id;
- short nameid;
- short amount;
- unsigned short equip;
- char identify;
- char refine;
- char attribute;
- short card[4];
-};
-enum {
- TABLE_INVENTORY,
- TABLE_CART,
- TABLE_STORAGE,
- TABLE_GUILD_STORAGE,
-};
-struct itemtemp{
- struct itemtmp equip[MAX_GUILD_STORAGE],notequip[MAX_GUILD_STORAGE];
-};
-int memitemdata_to_sql(struct itemtmp mapitem[], int count, int char_id,int tableswitch);
-
-//int memitemdataNEW_to_sql(struct itemtmp mapitem[], int count, int char_id,int tableswitch);
-int mapif_sendall(unsigned char *buf,unsigned int len);
-int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len);
-int mapif_send(int fd,unsigned char *buf,unsigned int len);
-
-int char_married(int pl1,int pl2);
-int char_child(int parent_id, int child_id);
-int char_family(int pl1,int pl2,int pl3);
-
-int char_loadName(int char_id, char* name);
-
-int request_accreg2(int account_id, int char_id);
-int save_accreg2(unsigned char* buf, int len);
-
-extern int char_name_option;
-extern char char_name_letters[];
-extern bool char_gm_read;
-extern int autosave_interval;
-extern int save_log;
-extern int charsave_method;
-extern char db_path[];
-extern char char_db[256];
-extern char scdata_db[256];
-extern char cart_db[256];
-extern char inventory_db[256];
-extern char charlog_db[256];
-extern char storage_db[256];
-extern char interlog_db[256];
-extern char reg_db[256];
-extern char skill_db[256];
-extern char memo_db[256];
-extern char guild_db[256];
-extern char guild_alliance_db[256];
-extern char guild_castle_db[256];
-extern char guild_expulsion_db[256];
-extern char guild_member_db[256];
-extern char guild_position_db[256];
-extern char guild_skill_db[256];
-extern char guild_storage_db[256];
-extern char party_db[256];
-extern char pet_db[256];
-
-extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris]
-extern int connection_ping_interval;
-
-extern char login_db_level[32];
-extern char login_db_account_id[32];
-
-extern int lowest_gm_level;
-extern int GM_num;
-extern struct gm_account *gm_account;
-
-extern int guild_exp_rate;
-extern int log_inter;
-
-extern int debug_mysql_query(char *file, int line, void *mysql, const char *q);
-
-//Exported for use in the TXT-SQL converter.
-int mmo_char_tosql(int char_id, struct mmo_charstatus *p);
-void sql_config_read(const char *cfgName);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+#ifndef _CHARSQL_H_
+#define _CHARSQL_H_
+
+#include "../common/core.h"
+#include "../common/socket.h"
+#include "../common/timer.h"
+#include "../common/mmo.h"
+#include "../common/version.h"
+#include "../common/db.h"
+#include "../common/mapindex.h"
+
+#include "inter.h"
+#include "int_pet.h"
+#include "int_guild.h"
+#include "int_party.h"
+#include "int_storage.h"
+#include "itemdb.h"
+
+#define START_CHAR_NUM 150000
+#define MAX_MAP_SERVERS 30
+
+#define LAN_CONF_NAME "conf/subnet_athena.conf"
+
+#define DEFAULT_AUTOSAVE_INTERVAL 300*1000
+
+struct itemtmp {
+ int flag;//checked = 1 else 0
+ int id;
+ short nameid;
+ short amount;
+ unsigned short equip;
+ char identify;
+ char refine;
+ char attribute;
+ short card[4];
+};
+enum {
+ TABLE_INVENTORY,
+ TABLE_CART,
+ TABLE_STORAGE,
+ TABLE_GUILD_STORAGE,
+};
+struct itemtemp{
+ struct itemtmp equip[MAX_GUILD_STORAGE],notequip[MAX_GUILD_STORAGE];
+};
+int memitemdata_to_sql(struct itemtmp mapitem[], int count, int char_id,int tableswitch);
+
+//int memitemdataNEW_to_sql(struct itemtmp mapitem[], int count, int char_id,int tableswitch);
+int mapif_sendall(unsigned char *buf,unsigned int len);
+int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len);
+int mapif_send(int fd,unsigned char *buf,unsigned int len);
+
+int char_married(int pl1,int pl2);
+int char_child(int parent_id, int child_id);
+int char_family(int pl1,int pl2,int pl3);
+
+int char_loadName(int char_id, char* name);
+
+int request_accreg2(int account_id, int char_id);
+int save_accreg2(unsigned char* buf, int len);
+
+extern int char_name_option;
+extern char char_name_letters[];
+extern bool char_gm_read;
+extern int autosave_interval;
+extern int save_log;
+extern int charsave_method;
+extern char db_path[];
+extern char char_db[256];
+extern char scdata_db[256];
+extern char cart_db[256];
+extern char inventory_db[256];
+extern char charlog_db[256];
+extern char storage_db[256];
+extern char interlog_db[256];
+extern char reg_db[256];
+extern char skill_db[256];
+extern char memo_db[256];
+extern char guild_db[256];
+extern char guild_alliance_db[256];
+extern char guild_castle_db[256];
+extern char guild_expulsion_db[256];
+extern char guild_member_db[256];
+extern char guild_position_db[256];
+extern char guild_skill_db[256];
+extern char guild_storage_db[256];
+extern char party_db[256];
+extern char pet_db[256];
+
+extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris]
+extern int connection_ping_interval;
+
+extern char login_db_level[32];
+extern char login_db_account_id[32];
+
+extern int lowest_gm_level;
+extern int GM_num;
+extern struct gm_account *gm_account;
+
+extern int guild_exp_rate;
+extern int log_inter;
+
+extern int debug_mysql_query(char *file, int line, void *mysql, const char *q);
+
+//Exported for use in the TXT-SQL converter.
+int mmo_char_tosql(int char_id, struct mmo_charstatus *p);
+void sql_config_read(const char *cfgName);
+#endif
diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c
index 8920ed948..dbb9bc1ad 100644
--- a/src/char_sql/int_guild.c
+++ b/src/char_sql/int_guild.c
@@ -1,2106 +1,2106 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by hack
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-
-#include "char.h"
-#include "../common/strlib.h"
-#include "../common/showmsg.h"
-// #include "int_storage.h"
-#include "inter.h"
-#include "int_guild.h"
-#include "mmo.h"
-#include "socket.h"
-#include "db.h"
-#include "malloc.h"
-
-#define GS_MEMBER_UNMODIFIED 0x00
-#define GS_MEMBER_MODIFIED 0x01
-#define GS_MEMBER_NEW 0x02
-
-#define GS_POSITION_UNMODIFIED 0x00
-#define GS_POSITION_MODIFIED 0x01
-
-// LSB = 0 => Alliance, LSB = 1 => Opposition
-#define GUILD_ALLIANCE_TYPE_MASK 0x01
-#define GUILD_ALLIANCE_REMOVE 0x08
-
-static char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
-
-#ifndef TXT_SQL_CONVERT
-//Guild cache
-static struct dbt *guild_db_;
-
-struct guild_castle castles[MAX_GUILDCASTLE];
-
-static unsigned int guild_exp[100];
-
-int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes);
-int mapif_guild_broken(int guild_id,int flag);
-int guild_check_empty(struct guild *g);
-int guild_calcinfo(struct guild *g);
-int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len);
-int mapif_guild_info(int fd,struct guild *g);
-int guild_break_sub(int key,void *data,va_list ap);
-int inter_guild_tosql(struct guild *g,int flag);
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-static int guild_save(DBKey key, void *data, va_list ap) {
- struct guild *g = (struct guild*) data;
- int *last_id = va_arg(ap, int *);
- int *state = va_arg(ap, int *);
-
- if ((*state) == 0 && g->guild_id == (*last_id))
- (*state)++; //Save next guild in the list.
- else if (g->save_flag&GS_MASK && (*state) == 1) {
- inter_guild_tosql(g, g->save_flag&GS_MASK);
- g->save_flag &= ~GS_MASK;
-
- //Some guild saved.
- (*last_id) = g->guild_id;
- (*state)++;
- }
-
- if(g->save_flag == GS_REMOVE) { //Nothing to save, guild is ready for removal.
- if (save_log)
- ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name);
- db_remove(guild_db_, key);
- }
- return 0;
-}
-
-static int guild_save_timer(int tid, unsigned int tick, int id, int data) {
- static int last_id = 0; //To know in which guild we were.
- int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving.
- if (!last_id) //Save the first guild in the list.
- state = 1;
- guild_db_->foreach(guild_db_, guild_save, &last_id, &state);
- if (state != 2) //Reached the end of the guild db without saving.
- last_id = 0; //Reset guild saved, return to beginning.
-
- state = guild_db_->size(guild_db_);
- if (state < 1) state = 1; //Calculate the time slot for the next save.
- add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0);
- return 0;
-}
-
-int inter_guild_removemember_tosql(int account_id, int char_id)
-{
- sprintf(tmp_sql,"DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql,"UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return 0;
-}
-#endif //TXT_SQL_CONVERT
-// Save guild into sql
-int inter_guild_tosql(struct guild *g,int flag)
-{
- // Table guild (GS_BASIC_MASK)
- // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data`
- // GS_CONNECT `connect_member`,`average_lv`
- // GS_MES `mes1`,`mes2`
- // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point`
- // GS_BASIC `name`,`master`,`char_id`
-
- // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`rsv1`,`rsv2`,`name`)
- // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`)
- // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`)
- // GS_EXPULSION `guild_expulsion` (`guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3`)
- // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`)
-
- // temporary storage for str convertion. They must be twice the size of the
- // original string to ensure no overflows will occur. [Skotlex]
- char t_name[NAME_LENGTH*2],
- t_master[NAME_LENGTH*2],
- t_mes1[120],
- t_mes2[240],
- t_member[NAME_LENGTH*2],
- t_position[NAME_LENGTH*2],
- t_alliance[NAME_LENGTH*2],
- t_ename[NAME_LENGTH*2],
- t_emes[80],
- t_info[240];
- char emblem_data[4096];
- char new_guild = 0;
- int i=0, sql_index;
-
- if (g->guild_id<=0 && g->guild_id != -1) return 0;
-
-#ifdef NOISY
- ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag);
-#endif
-
- jstrescapecpy(t_name, g->name);
-
- t_info[0]='\0';
-
-#ifndef TXT_SQL_CONVERT
- // Insert a new guild the guild
- if (flag&GS_BASIC && g->guild_id == -1)
- {
- strcat(t_info, " guild_create");
-
- // Create a new guild
- sprintf(tmp_sql,"INSERT INTO `%s` "
- "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) "
- "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')",
- guild_db,t_name,jstrescapecpy(t_master,g->master),g->guild_lv,g->max_member,g->average_lv,g->member[0].char_id);
- if(mysql_query(&mysql_handle, tmp_sql) )
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- if (g->guild_id == -1)
- return 0; //Failed to create guild!
- }
- else
- {
- //New guild, catch id
- if(mysql_field_count(&mysql_handle) == 0 && mysql_insert_id(&mysql_handle) != 0)
- {
- g->guild_id = (int)mysql_insert_id(&mysql_handle);
- new_guild = 1;
- }
- else
- return 0; //Failed to get ID??
- }
- }
-#else
- // Insert a new guild the guild
- if (flag&GS_BASIC)
- {
- strcat(t_info, " guild_create");
- // Since the PK is guild id + master id, a replace will not be enough if we are overwriting data, we need to wipe the previous guild.
- sprintf(tmp_sql,"DELETE FROM `%s` where `guild_id` = '%d'", guild_db,g->guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) )
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- // Create a new guild
- sprintf(tmp_sql,"REPLACE INTO `%s` "
- "(`guild_id`,`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) "
- "VALUES ('%d', '%s', '%s', '%d', '%d', '%d', '%d')",
- guild_db,g->guild_id,t_name,jstrescapecpy(t_master,g->master),g->guild_lv,g->max_member,g->average_lv,g->member[0].char_id);
- if(mysql_query(&mysql_handle, tmp_sql) )
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0; //Failed to create guild.
- }
- }
-#endif //TXT_SQL_CONVERT
- // If we need an update on an existing guild or more update on the new guild
- if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild))
- {
- sql_index = sprintf(tmp_sql,"UPDATE `%s` SET ", guild_db);
-
- if (flag & GS_EMBLEM)
- {
- char * pData = emblem_data;
- strcat(t_info, " emblem");
- // Convert emblem_data to hex
- for(i=0; i<g->emblem_len; i++){
- *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F];
- *pData++ = dataToHex[g->emblem_data[i] & 0x0F];
- }
- *pData = 0;
- sql_index += sprintf(tmp_sql + sql_index,"`emblem_len`=%d,`emblem_id`=%d,`emblem_data`='%s',",g->emblem_len,g->emblem_id,emblem_data);
- }
- if (flag & GS_BASIC)
- {
- strcat(t_info, " basic");
- sql_index += sprintf(tmp_sql + sql_index,"`name`='%s', `master`='%s', `char_id`=%d,",t_name,jstrescapecpy(t_master,g->master),g->member[0].char_id);
- }
- if (flag & GS_CONNECT)
- {
- strcat(t_info, " connect");
- sql_index += sprintf(tmp_sql + sql_index,"`connect_member`=%d,`average_lv`=%d,",g->connect_member, g->average_lv);
- }
- if (flag & GS_MES)
- {
- strcat(t_info, " mes");
- sql_index += sprintf(tmp_sql + sql_index,"`mes1`='%s',`mes2`='%s',",jstrescapecpy(t_mes1,g->mes1),jstrescapecpy(t_mes2,g->mes2));
- }
- if (flag & GS_LEVEL)
- {
- strcat(t_info, " level");
- sql_index += sprintf(tmp_sql + sql_index,"`guild_lv`=%d,`skill_point`=%d,`exp`=%u,`next_exp`=%u,`max_member`=%d,",g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member);
- }
- sprintf(tmp_sql + sql_index -1," WHERE `guild_id`=%d", g->guild_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- if (flag&GS_MEMBER)
- {
- struct guild_member *m;
- strcat(t_info, " members");
- // Update only needed players
- for(i=0;i<g->max_member;i++){
- m = &g->member[i];
-#ifndef TXT_SQL_CONVERT
- if (!m->modified)
- continue;
-#endif
- if(m->account_id) {
- //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO
- sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) "
- "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%u','%d','%d','%d','%s')",
- guild_member_db, g->guild_id, m->account_id,m->char_id,
- m->hair,m->hair_color,m->gender,
- m->class_,m->lv,m->exp,m->exp_payper,m->online,m->position,
- jstrescapecpy(t_member,m->name));
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- if (m->modified & GS_MEMBER_NEW)
- {
- sprintf(tmp_sql,"UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'",
- char_db, g->guild_id, m->char_id);
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- m->modified = GS_MEMBER_UNMODIFIED;
- }
- }
- }
-
- if (flag&GS_POSITION){
- strcat(t_info, " positions");
- //printf("- Insert guild %d to guild_position\n",g->guild_id);
- for(i=0;i<MAX_GUILDPOSITION;i++){
- struct guild_position *p = &g->position[i];
-#ifndef TXT_SQL_CONVERT
- if (!p->modified)
- continue;
-#endif
- sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d', '%s','%d','%d')",
- guild_position_db, g->guild_id, i, jstrescapecpy(t_position,p->name),p->mode,p->exp_mode);
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- p->modified = GS_POSITION_UNMODIFIED;
- }
- }
-
- if (flag&GS_ALLIANCE)
- {
- // Delete current alliances
- // NOTE: no need to do it on both sides since both guilds in memory had
- // their info changed, not to mention this would also mess up oppositions!
- // [Skotlex]
-// sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'",guild_alliance_db, g->guild_id,g->guild_id);
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_alliance_db, g->guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) )
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- else
- {
- //printf("- Insert guild %d to guild_alliance\n",g->guild_id);
- for(i=0;i<MAX_GUILDALLIANCE;i++)
- {
- struct guild_alliance *a=&g->alliance[i];
- if(a->guild_id>0)
- {
- sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) "
- "VALUES ('%d','%d','%d','%s')",
- guild_alliance_db, g->guild_id,a->opposition,a->guild_id,jstrescapecpy(t_alliance,a->name));
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) )
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- }
- }
-
- if (flag&GS_EXPULSION){
- strcat(t_info, " expulsions");
- //printf("- Insert guild %d to guild_expulsion\n",g->guild_id);
- for(i=0;i<MAX_GUILDEXPULSION;i++){
- struct guild_expulsion *e=&g->expulsion[i];
- if(e->account_id>0){
- sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3`) "
- "VALUES ('%d','%s','%s','%s','%d','%d','%d','%d')",
- guild_expulsion_db, g->guild_id,
- jstrescapecpy(t_ename,e->name),jstrescapecpy(t_emes,e->mes),e->acc,e->account_id,e->rsv1,e->rsv2,e->rsv3 );
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- }
-
- if (flag&GS_SKILL){
- strcat(t_info, " skills");
- //printf("- Insert guild %d to guild_skill\n",g->guild_id);
- for(i=0;i<MAX_GUILDSKILL;i++){
- if (g->skill[i].id>0 && g->skill[i].lv>0){
- sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')",
- guild_skill_db, g->guild_id,g->skill[i].id,g->skill[i].lv);
- //printf("%s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- }
-
- if (save_log)
- ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info);
- return 1;
-}
-#ifndef TXT_SQL_CONVERT
-// Read guild from sql
-struct guild * inter_guild_fromsql(int guild_id)
-{
- int i;
- char * pstr, * pEmblemData;
- struct guild *g;
-
- if (guild_id<=0) return NULL;
-
- g = idb_get(guild_db_,guild_id);
- if (g) return g;
-
- g = (struct guild*)aCalloc(sizeof(struct guild), 1);
-
-#ifdef NOISY
- ShowInfo("Guild load request (%d)...\n", guild_id);
-#endif
-
- sprintf(tmp_sql,"SELECT `name`,`master`,`guild_lv`,`connect_member`,`max_member`,`average_lv`,`exp`,`next_exp`,`skill_point`,`mes1`,`mes2`,`emblem_len`,`emblem_id`,`emblem_data` "
- "FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res==NULL || mysql_num_rows(sql_res)<1) {
- //Guild does not exists.
- if (sql_res) mysql_free_result(sql_res);
- aFree(g);
- return NULL;
- }
-
- sql_row = mysql_fetch_row(sql_res);
- if (sql_row==NULL) {
- mysql_free_result(sql_res);
- aFree(g);
- return NULL;
- }
-
- g->guild_id=guild_id;
- strncpy(g->name,sql_row[0],NAME_LENGTH-1);
- strncpy(g->master,sql_row[1],NAME_LENGTH-1);
- g->guild_lv=atoi(sql_row[2]);
- g->connect_member=atoi(sql_row[3]);
- g->max_member = atoi(sql_row[4]);
- if (g->max_member > MAX_GUILD)
- { // Fix reduction of MAX_GUILD [PoW]
- ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD);
- g->max_member = MAX_GUILD;
- }
- g->average_lv=atoi(sql_row[5]);
- g->exp=(unsigned int)atof(sql_row[6]);
- g->next_exp=(unsigned int)atof(sql_row[7]);
- g->skill_point=atoi(sql_row[8]);
- //There shouldn't be a need to copy the very last char, as it's the \0 [Skotlex]
- strncpy(g->mes1,sql_row[9],59);
- strncpy(g->mes2,sql_row[10],119);
- g->emblem_len=atoi(sql_row[11]);
- g->emblem_id=atoi(sql_row[12]);
- for(i=0,pstr=sql_row[13],pEmblemData=g->emblem_data; i < g->emblem_len; i++,pstr+=2){
- int c1=pstr[0],c2=pstr[1],x1=0,x2=0;
- if(c1>='0' && c1<='9')
- x1=c1-'0';
- else if(c1>='a' && c1<='f')
- x1=c1-'a'+10;
- else if(c1>='A' && c1<='F')
- x1=c1-'A'+10;
- if(c2>='0' && c2<='9')
- x2=c2-'0';
- else if(c2>='a' && c2<='f')
- x2=c2-'a'+10;
- else if(c2>='A' && c2<='F')
- x2=c2-'A'+10;
- *pEmblemData++=(x1<<4)|x2;
- }
- mysql_free_result(sql_res);
-
- //printf("- Read guild_member %d from sql \n",guild_id);
- sprintf(tmp_sql,"SELECT `guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`rsv1`,`rsv2`,`name` "
- "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id);
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res) {
- for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<g->max_member);i++){
- struct guild_member *m = &g->member[i];
- m->account_id=atoi(sql_row[1]);
- m->char_id=atoi(sql_row[2]);
- m->hair=atoi(sql_row[3]);
- m->hair_color=atoi(sql_row[4]);
- m->gender=atoi(sql_row[5]);
- m->class_=atoi(sql_row[6]);
- m->lv=atoi(sql_row[7]);
- m->exp=strtoul(sql_row[8],NULL,10);
- m->exp_payper=atoi(sql_row[9]);
- m->online=atoi(sql_row[10]);
- m->position = atoi(sql_row[11]);
- if (m->position >= MAX_GUILDPOSITION) // Fix reduction of MAX_GUILDPOSITION [PoW]
- m->position = MAX_GUILDPOSITION - 1;
-
- strncpy(m->name,sql_row[14],NAME_LENGTH-1);
- m->modified = GS_MEMBER_UNMODIFIED;
- }
- mysql_free_result(sql_res);
- }
-
- //printf("- Read guild_position %d from sql \n",guild_id);
- sprintf(tmp_sql,"SELECT `guild_id`,`position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'",guild_position_db, guild_id);
- //printf(" %s\n",tmp_sql);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res) {
- for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDPOSITION);i++){
- int position = atoi(sql_row[1]);
- struct guild_position *p = &g->position[position];
- strncpy(p->name,sql_row[2],NAME_LENGTH-1);
- p->mode=atoi(sql_row[3]);
- p->exp_mode=atoi(sql_row[4]);
- p->modified = GS_POSITION_UNMODIFIED;
- }
- mysql_free_result(sql_res);
- }
-
- //printf("- Read guild_alliance %d from sql \n",guild_id);
- sprintf(tmp_sql,"SELECT `guild_id`,`opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'",guild_alliance_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res) {
- for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDALLIANCE);i++){
- struct guild_alliance *a = &g->alliance[i];
- a->opposition=atoi(sql_row[1]);
- a->guild_id=atoi(sql_row[2]);
- strncpy(a->name,sql_row[3],NAME_LENGTH-1);
- }
- mysql_free_result(sql_res);
- }
-
- //printf("- Read guild_expulsion %d from sql \n",guild_id);
- sprintf(tmp_sql,"SELECT `guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3` FROM `%s` WHERE `guild_id`='%d'",guild_expulsion_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res) {
- for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDEXPULSION);i++){
- struct guild_expulsion *e = &g->expulsion[i];
-
- strncpy(e->name,sql_row[1],NAME_LENGTH-1);
- //No need to copy char 40, the null terminator. [Skotlex]
- strncpy(e->mes,sql_row[2],39);
- strncpy(e->acc,sql_row[3],39);
- e->account_id=atoi(sql_row[4]);
- e->rsv1=atoi(sql_row[5]);
- e->rsv2=atoi(sql_row[6]);
- e->rsv3=atoi(sql_row[7]);
- }
- mysql_free_result(sql_res);
- }
-
- //printf("- Read guild_skill %d from sql \n",guild_id);
- sprintf(tmp_sql,"SELECT `guild_id`,`id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`",guild_skill_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- aFree(g);
- return NULL;
- }
-
- for(i = 0; i < MAX_GUILDSKILL; i++)
- { //Skill IDs must always be initialized. [Skotlex]
- g->skill[i].id = i + GD_SKILLBASE;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res) {
- while ((sql_row = mysql_fetch_row(sql_res))){
- int id = atoi(sql_row[1])-GD_SKILLBASE;
- if (id >= 0 && id < MAX_GUILDSKILL)
- //I know this seems ridiculous, but the skills HAVE to be placed on their 'correct' array slot or things break x.x [Skotlex]
- g->skill[id].lv=atoi(sql_row[2]);
- }
- mysql_free_result(sql_res);
- }
-
- idb_put(guild_db_, guild_id, g); //Add to cache
- g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long.
-
- if (save_log)
- ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name);
-
- return g;
-}
-
-#endif //TXT_SQL_CONVERT
-int inter_guildcastle_tosql(struct guild_castle *gc){
- // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`)
-
- if (gc==NULL) return 0;
- #ifdef GUILD_DEBUG
-ShowDebug("Save guild_castle (%d)\n", gc->castle_id);
- #endif
-
-// sql_query("DELETE FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, gc->castle_id);
-
- sprintf(tmp_sql,"REPLACE INTO `%s` "
- "(`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`,"
- "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`,"
- "`Ghp0`, `Ghp1`, `Ghp2`, `Ghp3`, `Ghp4`, `Ghp5`, `Ghp6`, `Ghp7`)"
- "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d')",
- guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime,
- gc->createTime, gc->visibleC,
- gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible,
- gc->guardian[0].hp, gc->guardian[1].hp, gc->guardian[2].hp, gc->guardian[3].hp, gc->guardian[4].hp, gc->guardian[5].hp, gc->guardian[6].hp, gc->guardian[7].hp);
-
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
-#ifndef TXT_SQL_CONVERT
- memcpy(&castles[gc->castle_id],gc,sizeof(struct guild_castle));
-#endif //TXT_SQL_CONVERT
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-
-// Read guild_castle from sql
-int inter_guildcastle_fromsql(int castle_id,struct guild_castle *gc)
-{
- static int castles_init=0;
- if (gc==NULL) return 0;
- if (castle_id==-1) return 0;
-
- if(!castles_init)
- {
- int i;
- for(i=0;i<MAX_GUILDCASTLE;i++)
- castles[i].castle_id=-1;
- castles_init = 1;
- }
-
- if(castles[castle_id].castle_id == castle_id)
- {
- memcpy(gc,&castles[castle_id],sizeof(struct guild_castle));
- return 1;
- }
-
- memset(gc,0,sizeof(struct guild_castle));
- sprintf(tmp_sql,"SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, "
- "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`,"
- "`Ghp0`, `Ghp1`, `Ghp2`, `Ghp3`, `Ghp4`, `Ghp5`, `Ghp6`, `Ghp7`"
- " FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, castle_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- // ARU: This needs to be set even if there are no SQL results
- gc->castle_id=castle_id;
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
- sql_row = mysql_fetch_row(sql_res);
- if (sql_row==NULL){
- mysql_free_result(sql_res);
- return 1; //Assume empty castle.
- }
- gc->guild_id = atoi (sql_row[1]);
- gc->economy = atoi (sql_row[2]);
- gc->defense = atoi (sql_row[3]);
- gc->triggerE = atoi (sql_row[4]);
- gc->triggerD = atoi (sql_row[5]);
- gc->nextTime = atoi (sql_row[6]);
- gc->payTime = atoi (sql_row[7]);
- gc->createTime = atoi (sql_row[8]);
- gc->visibleC = atoi (sql_row[9]);
- gc->guardian[0].visible = atoi (sql_row[10]);
- gc->guardian[1].visible = atoi (sql_row[11]);
- gc->guardian[2].visible = atoi (sql_row[12]);
- gc->guardian[3].visible = atoi (sql_row[13]);
- gc->guardian[4].visible = atoi (sql_row[14]);
- gc->guardian[5].visible = atoi (sql_row[15]);
- gc->guardian[6].visible = atoi (sql_row[16]);
- gc->guardian[7].visible = atoi (sql_row[17]);
- gc->guardian[0].hp = atoi (sql_row[18]);
- gc->guardian[1].hp = atoi (sql_row[19]);
- gc->guardian[2].hp = atoi (sql_row[20]);
- gc->guardian[3].hp = atoi (sql_row[21]);
- gc->guardian[4].hp = atoi (sql_row[22]);
- gc->guardian[5].hp = atoi (sql_row[23]);
- gc->guardian[6].hp = atoi (sql_row[24]);
- gc->guardian[7].hp = atoi (sql_row[25]);
-
- if (save_log)
- ShowInfo("Loaded Castle %d (guild %d)\n",castle_id,gc->guild_id);
-
- }
- mysql_free_result(sql_res) ; //resource free
-
- memcpy(&castles[castle_id],gc,sizeof(struct guild_castle));
-
- return 1;
-}
-
-
-// Read exp_guild.txt
-int inter_guild_ReadEXP(void)
-{
- int i;
- FILE *fp;
- char line[1024];
- for (i=0;i<100;i++) guild_exp[i]=0;
-
- sprintf(line, "%s/exp_guild.txt", db_path);
- fp=fopen(line,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", line);
- return 1;
- }
- i=0;
- while(fgets(line,256,fp) && i<100){
- if(line[0]=='/' && line[1]=='/')
- continue;
- guild_exp[i]=(unsigned int)atof(line);
- i++;
- }
- fclose(fp);
-
- return 0;
-}
-
-
-int inter_guild_CharOnline(int char_id, int guild_id) {
-
- struct guild *g;
- int i;
-
- if (guild_id == -1) {
- //Get guild_id from the database
- sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if(sql_res == NULL)
- return 0; //Eh? No guild?
-
- sql_row = mysql_fetch_row(sql_res);
- guild_id = sql_row?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
- }
- if (guild_id == 0)
- return 0; //No guild...
-
- g = inter_guild_fromsql(guild_id);
- if(!g) {
- ShowError("Character %d's guild %d not found!\n", char_id, guild_id);
- return 0;
- }
-
- //Member has logged in before saving, tell saver not to delete
- if(g->save_flag & GS_REMOVE)
- g->save_flag &= ~GS_REMOVE;
-
- //Set member online
- for(i=0; i<g->max_member; i++) {
- if (g->member[i].char_id == char_id) {
- g->member[i].online = 1;
- g->member[i].modified = GS_MEMBER_MODIFIED;
- break;
- }
- }
- return 1;
-}
-
-int inter_guild_CharOffline(int char_id, int guild_id) {
- struct guild *g=NULL;
- int online_count=0, i;
-
- if (guild_id == -1) {
- //Get guild_id from the database
- sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if(sql_res == NULL)
- return 0; //Eh? No guild?
-
- sql_row = mysql_fetch_row(sql_res);
- guild_id = sql_row?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
- }
- if (guild_id == 0)
- return 0; //No guild...
-
- //Character has a guild, set character offline and check if they were the only member online
- g = inter_guild_fromsql(guild_id);
- if (g == NULL) //Guild not found?
- return 0;
-
- //Set member offline
- for(i=0; i<g->max_member; i++) {
- if(g->member[i].char_id == char_id)
- {
- g->member[i].online = 0;
- g->member[i].modified = GS_MEMBER_MODIFIED;
- }
- if(g->member[i].online && !online_count)
- online_count++;
- }
-
- // Remove guild from memory if no players online
- if(online_count == 0)
- g->save_flag |= GS_REMOVE;
-
- return 1;
-}
-
-// Initialize guild sql
-int inter_guild_sql_init(void)
-{
- //Initialize the guild cache
- guild_db_= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
-
- //Read exp file
- inter_guild_ReadEXP();
-
- add_timer_func_list(guild_save_timer, "guild_save_timer");
- add_timer(gettick() + 10000, guild_save_timer, 0, 0);
- return 0;
-}
-
-static int guild_db_final(DBKey key, void *data, va_list ap)
-{
- struct guild *g = (struct guild*)data;
- if (g->save_flag&GS_MASK) {
- inter_guild_tosql(g, g->save_flag&GS_MASK);
- return 1;
- }
- return 0;
-}
-
-void inter_guild_sql_final(void)
-{
- guild_db_->destroy(guild_db_, guild_db_final);
- return;
-}
-
-// Get guild_id by its name. Returns 0 if not found, -1 on error.
-int search_guildname(char *str)
-{
- int guild_id;
- char t_name[NAME_LENGTH*2];
-
- jstrescapecpy(t_name, str);
- //Lookup guilds with the same name
- sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, t_name);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return -1;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if(sql_res)
- sql_row = mysql_fetch_row(sql_res);
-
- guild_id = (sql_row&&sql_res&&sql_row[0])?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
- return guild_id;
-}
-
-// Check if guild is empty
-int guild_check_empty(struct guild *g)
-{
- int i;
- for(i=0;i<g->max_member;i++){
- if(g->member[i].account_id>0){
- return 0;
- }
- }
- //Let the calling function handle the guild removal in case they need
- //to do something else with it before freeing the data. [Skotlex]
- return 1;
-}
-
-unsigned int guild_nextexp(int level)
-{
- if (level == 0)
- return 1;
- if (level < 100 && level > 0) // Change by hack
- return guild_exp[level-1];
-
- return 0;
-}
-
-int guild_checkskill(struct guild *g,int id) {
-
- int idx = id - GD_SKILLBASE;
-
- if(idx < 0 || idx >= MAX_GUILDSKILL)
- return 0;
-
- return g->skill[idx].lv;
-}
-
-int guild_calcinfo(struct guild *g)
-{
- int i,c;
- unsigned int nextexp;
- struct guild before = *g; // Save guild current values
-
- if(g->guild_lv<=0)
- g->guild_lv = 1;
- nextexp = guild_nextexp(g->guild_lv);
-
- // Consume guild exp and increase guild level
- while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin]
- g->exp-=nextexp;
- g->guild_lv++;
- g->skill_point++;
- nextexp = guild_nextexp(g->guild_lv);
- }
-
- // Save next exp step
- g->next_exp = nextexp;
-
- // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv.
- g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6;
- if(g->max_member > MAX_GUILD)
- {
- ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD);
- g->max_member = MAX_GUILD;
- }
-
- // Compute the guild average level level
- g->average_lv=0;
- g->connect_member=0;
- for(i=c=0;i<g->max_member;i++)
- {
- if(g->member[i].account_id>0)
- {
- if (g->member[i].lv >= 0)
- {
- g->average_lv+=g->member[i].lv;
- c++;
- }
- else
- {
- ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv);
- }
-
- if(g->member[i].online)
- g->connect_member++;
- }
- }
- if(c)
- g->average_lv /= c;
-
- // Check if guild stats has change
- if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point )
- {
- g->save_flag |= GS_LEVEL;
- mapif_guild_info(-1,g);
- return 1;
- }
-
- return 0;
-}
-
-//-------------------------------------------------------------------
-// Packet sent to map server
-
-int mapif_guild_created(int fd,int account_id,struct guild *g)
-{
- WFIFOHEAD(fd, 10);
- WFIFOW(fd,0)=0x3830;
- WFIFOL(fd,2)=account_id;
- if(g != NULL)
- {
- WFIFOL(fd,6)=g->guild_id;
- ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name);
- } else
- WFIFOL(fd,6)=0;
-
- WFIFOSET(fd,10);
- return 0;
-}
-// Guild not found
-int mapif_guild_noinfo(int fd,int guild_id)
-{
- unsigned char buf[12];
- WBUFW(buf,0)=0x3831;
- WBUFW(buf,2)=8;
- WBUFL(buf,4)=guild_id;
- ShowWarning("int_guild: info not found %d\n",guild_id);
- if(fd<0)
- mapif_sendall(buf,8);
- else
- mapif_send(fd,buf,8);
- return 0;
-}
-
-// Send guild info
-int mapif_guild_info(int fd,struct guild *g)
-{
- unsigned char buf[8+sizeof(struct guild)];
- WBUFW(buf,0)=0x3831;
- WBUFW(buf,2)=4+sizeof(struct guild);
- memcpy(buf+4,g,sizeof(struct guild));
- if(fd<0)
- mapif_sendall(buf,WBUFW(buf,2));
- else
- mapif_send(fd,buf,WBUFW(buf,2));
- return 0;
-}
-
-// ACK member add
-int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag)
-{
- WFIFOHEAD(fd, 15);
- WFIFOW(fd,0)=0x3832;
- WFIFOL(fd,2)=guild_id;
- WFIFOL(fd,6)=account_id;
- WFIFOL(fd,10)=char_id;
- WFIFOB(fd,14)=flag;
- WFIFOSET(fd,15);
- return 0;
-}
-
-// ACK member leave
-int mapif_guild_leaved(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes)
-{
- unsigned char buf[55+NAME_LENGTH];
- WBUFW(buf, 0)=0x3834;
- WBUFL(buf, 2)=guild_id;
- WBUFL(buf, 6)=account_id;
- WBUFL(buf,10)=char_id;
- WBUFB(buf,14)=flag;
- memcpy(WBUFP(buf,15),mes,40);
- memcpy(WBUFP(buf,55),name,NAME_LENGTH);
- mapif_sendall(buf,55+NAME_LENGTH);
- ShowInfo("int_guild: guild leaved (%d - %d: %s - %s)\n",guild_id,account_id,name,mes);
- return 0;
-}
-
-// Send short member's info
-int mapif_guild_memberinfoshort(struct guild *g,int idx)
-{
- unsigned char buf[19];
- WBUFW(buf, 0)=0x3835;
- WBUFL(buf, 2)=g->guild_id;
- WBUFL(buf, 6)=g->member[idx].account_id;
- WBUFL(buf,10)=g->member[idx].char_id;
- WBUFB(buf,14)=(unsigned char)g->member[idx].online;
- WBUFW(buf,15)=g->member[idx].lv;
- WBUFW(buf,17)=g->member[idx].class_;
- mapif_sendall(buf,19);
- return 0;
-}
-
-// Send guild broken
-int mapif_guild_broken(int guild_id,int flag)
-{
- unsigned char buf[7];
- WBUFW(buf,0)=0x3836;
- WBUFL(buf,2)=guild_id;
- WBUFB(buf,6)=flag;
- mapif_sendall(buf,7);
- ShowInfo("int_guild: Guild broken (%d)\n",guild_id);
- return 0;
-}
-
-// Send guild message
-int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd)
-{
- unsigned char buf[512];
- if (len > 500)
- len = 500;
- WBUFW(buf,0)=0x3837;
- WBUFW(buf,2)=len+12;
- WBUFL(buf,4)=guild_id;
- WBUFL(buf,8)=account_id;
- memcpy(WBUFP(buf,12),mes,len);
- mapif_sendallwos(sfd, buf,len+12);
- return 0;
-}
-
-// Send basic info
-int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len)
-{
- unsigned char buf[2048];
- if (len > 2038)
- len = 2038;
- WBUFW(buf, 0)=0x3839;
- WBUFW(buf, 2)=len+10;
- WBUFL(buf, 4)=guild_id;
- WBUFW(buf, 8)=type;
- memcpy(WBUFP(buf,10),data,len);
- mapif_sendall(buf,len+10);
- return 0;
-}
-
-// Send member info
-int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len)
-{
- unsigned char buf[2048];
- if (len > 2030)
- len = 2030;
- WBUFW(buf, 0)=0x383a;
- WBUFW(buf, 2)=len+18;
- WBUFL(buf, 4)=guild_id;
- WBUFL(buf, 8)=account_id;
- WBUFL(buf,12)=char_id;
- WBUFW(buf,16)=type;
- memcpy(WBUFP(buf,18),data,len);
- mapif_sendall(buf,len+18);
- return 0;
-}
-
-// ACK guild skill up
-int mapif_guild_skillupack(int guild_id,int skill_num,int account_id)
-{
- unsigned char buf[14];
- WBUFW(buf, 0)=0x383c;
- WBUFL(buf, 2)=guild_id;
- WBUFL(buf, 6)=skill_num;
- WBUFL(buf,10)=account_id;
- mapif_sendall(buf,14);
- return 0;
-}
-
-// ACK guild alliance
-int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,
- int flag,const char *name1,const char *name2)
-{
- unsigned char buf[19+2*NAME_LENGTH];
- WBUFW(buf, 0)=0x383d;
- WBUFL(buf, 2)=guild_id1;
- WBUFL(buf, 6)=guild_id2;
- WBUFL(buf,10)=account_id1;
- WBUFL(buf,14)=account_id2;
- WBUFB(buf,18)=flag;
- memcpy(WBUFP(buf,19),name1,NAME_LENGTH);
- memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH);
- mapif_sendall(buf,19+2*NAME_LENGTH);
- return 0;
-}
-
-// Send a guild position desc
-int mapif_guild_position(struct guild *g,int idx)
-{
- unsigned char buf[12 + sizeof(struct guild_position)];
- WBUFW(buf,0)=0x383b;
- WBUFW(buf,2)=sizeof(struct guild_position)+12;
- WBUFL(buf,4)=g->guild_id;
- WBUFL(buf,8)=idx;
- memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position));
- mapif_sendall(buf,WBUFW(buf,2));
- return 0;
-}
-
-// Send the guild notice
-int mapif_guild_notice(struct guild *g)
-{
- unsigned char buf[256];
- WBUFW(buf,0)=0x383e;
- WBUFL(buf,2)=g->guild_id;
- memcpy(WBUFP(buf,6),g->mes1,60);
- memcpy(WBUFP(buf,66),g->mes2,120);
- mapif_sendall(buf,186);
- return 0;
-}
-
-// Send emblem data
-int mapif_guild_emblem(struct guild *g)
-{
- unsigned char buf[12 + sizeof(g->emblem_data)];
- WBUFW(buf,0)=0x383f;
- WBUFW(buf,2)=g->emblem_len+12;
- WBUFL(buf,4)=g->guild_id;
- WBUFL(buf,8)=g->emblem_id;
- memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len);
- mapif_sendall(buf,WBUFW(buf,2));
- return 0;
-}
-
-int mapif_guild_master_changed(struct guild *g, int position)
-{
- unsigned char buf[10];
- WBUFW(buf,0)=0x3843;
- WBUFL(buf,2)=g->guild_id;
- WBUFL(buf,6)=position;
- mapif_sendall(buf,10);
- return 0;
-}
-
-int mapif_guild_castle_dataload(int castle_id,int index,int value) // <Agit>
-{
- unsigned char buf[9];
- WBUFW(buf, 0)=0x3840;
- WBUFW(buf, 2)=castle_id;
- WBUFB(buf, 4)=index;
- WBUFL(buf, 5)=value;
- mapif_sendall(buf,9);
- return 0;
-}
-
-int mapif_guild_castle_datasave(int castle_id,int index,int value) // <Agit>
-{
- unsigned char buf[9];
- WBUFW(buf, 0)=0x3841;
- WBUFW(buf, 2)=castle_id;
- WBUFB(buf, 4)=index;
- WBUFL(buf, 5)=value;
- mapif_sendall(buf,9);
- return 0;
-}
-
-int mapif_guild_castle_alldataload(int fd) {
- struct guild_castle* gc = (struct guild_castle *)aMalloc(sizeof(struct guild_castle));
- int i, len = 4;
- WFIFOHEAD(fd, len + MAX_GUILDCASTLE*sizeof(struct guild_castle));
- WFIFOW(fd,0) = 0x3842;
- sprintf(tmp_sql,"SELECT * FROM `%s` ORDER BY `castle_id`", guild_castle_db);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- for(i = 0; ((sql_row = mysql_fetch_row(sql_res)) && i < MAX_GUILDCASTLE); i++) {
- memset(gc, 0, sizeof(struct guild_castle));
- gc->castle_id = atoi(sql_row[0]);
- gc->guild_id = atoi(sql_row[1]);
- gc->economy = atoi(sql_row[2]);
- gc->defense = atoi(sql_row[3]);
- gc->triggerE = atoi(sql_row[4]);
- gc->triggerD = atoi(sql_row[5]);
- gc->nextTime = atoi(sql_row[6]);
- gc->payTime = atoi(sql_row[7]);
- gc->createTime = atoi(sql_row[8]);
- gc->visibleC = atoi(sql_row[9]);
- gc->guardian[0].visible = atoi(sql_row[10]);
- gc->guardian[1].visible = atoi(sql_row[11]);
- gc->guardian[2].visible = atoi(sql_row[12]);
- gc->guardian[3].visible = atoi(sql_row[13]);
- gc->guardian[4].visible = atoi(sql_row[14]);
- gc->guardian[5].visible = atoi(sql_row[15]);
- gc->guardian[6].visible = atoi(sql_row[16]);
- gc->guardian[7].visible = atoi(sql_row[17]);
- gc->guardian[0].visible = atoi(sql_row[18]);
- gc->guardian[1].visible = atoi(sql_row[19]);
- gc->guardian[2].visible = atoi(sql_row[20]);
- gc->guardian[3].visible = atoi(sql_row[21]);
- gc->guardian[4].visible = atoi(sql_row[22]);
- gc->guardian[5].visible = atoi(sql_row[23]);
- gc->guardian[6].visible = atoi(sql_row[24]);
- gc->guardian[7].visible = atoi(sql_row[25]);
- memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle));
- len += sizeof(struct guild_castle);
- }
- mysql_free_result(sql_res);
- }
- WFIFOW(fd,2) = len;
- WFIFOSET(fd,len);
-
- aFree(gc);
-
- return 0;
-}
-
-
-//-------------------------------------------------------------------
-// Packet received from map server
-
-
-// ƒMƒ‹ƒhμ¬—v‹
-int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master)
-{
- struct guild *g;
- int i=0;
-#ifdef NOISY
- ShowInfo("Creating Guild (%s)\n", name);
-#endif
- if(search_guildname(name) != 0){
- ShowInfo("int_guild: guild with same name exists [%s]\n",name);
- mapif_guild_created(fd,account_id,NULL);
- return 0;
- }
- // Check Authorised letters/symbols in the name of the character
- if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
- for (i = 0; i < NAME_LENGTH && name[i]; i++)
- if (strchr(char_name_letters, name[i]) == NULL) {
- mapif_guild_created(fd,account_id,NULL);
- return 0;
- }
- } else if (char_name_option == 2) { // 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) {
- mapif_guild_created(fd,account_id,NULL);
- return 0;
- }
- }
-
- g = (struct guild *)aMalloc(sizeof(struct guild));
- memset(g,0,sizeof(struct guild));
-
- memcpy(g->name,name,NAME_LENGTH);
- memcpy(g->master,master->name,NAME_LENGTH);
- memcpy(&g->member[0],master,sizeof(struct guild_member));
- g->member[0].modified = GS_MEMBER_MODIFIED;
-
- // Set default positions
- g->position[0].mode=0x11;
- strcpy(g->position[0].name,"GuildMaster");
- strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie");
- for(i=1;i<MAX_GUILDPOSITION-1;i++)
- sprintf(g->position[i].name,"Position %d",i+1);
-
- // Initialize guild property
- g->max_member=16;
- g->average_lv=master->lv;
- for(i=0;i<MAX_GUILDSKILL;i++)
- g->skill[i].id=i + GD_SKILLBASE;
- g->guild_id= -1; //Request to create guild.
-
- // Create the guild
- if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) {
- //Failed to Create guild....
- ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master);
- mapif_guild_created(fd,account_id,NULL);
- aFree(g);
- return 0;
- }
- ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master);
-
- //Add to cache
- idb_put(guild_db_, g->guild_id, g);
-
- // Report to client
- mapif_guild_created(fd,account_id,g);
- mapif_guild_info(fd,g);
-
- if(log_inter)
- inter_log("guild %s (id=%d) created by master %s (id=%d)" RETCODE,
- name, g->guild_id, master->name, master->account_id );
-
- return 0;
-}
-
-// Return guild info to client
-int mapif_parse_GuildInfo(int fd,int guild_id)
-{
- struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex]
- if(g)
- {
- if (!guild_calcinfo(g))
- mapif_guild_info(fd,g);
- }
- else
- mapif_guild_noinfo(fd,guild_id); // Failed to load info
- return 0;
-}
-
-// Add member to guild
-int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m)
-{
- struct guild * g;
- int i;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL){
- // Failed to add
- mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1);
- return 0;
- }
-
- // Find an empty slot
- for(i=0;i<g->max_member;i++)
- {
- if(g->member[i].account_id==0)
- {
- memcpy(&g->member[i],m,sizeof(struct guild_member));
- g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED);
- mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0);
- if (!guild_calcinfo(g)) //Send members if it was not invoked.
- mapif_guild_info(fd,g);
-
- g->save_flag |= GS_MEMBER;
- if (g->save_flag&GS_REMOVE)
- g->save_flag&=~GS_REMOVE;
- return 0;
- }
- }
-
- // Failed to add
- mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1);
- return 0;
-}
-
-// Delete member from guild
-int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes)
-{
- struct guild * g = inter_guild_fromsql(guild_id);
-
- if(g){
- int i;
- // Find the member
- for(i=0;i<g->max_member;i++){
- if( g->member[i].account_id==account_id && g->member[i].char_id==char_id)
- {
- if(flag)
- {
- // Write expulsion reason
- int j;
- // Find an empty slot
- for(j=0;j<MAX_GUILDEXPULSION;j++){
- if(g->expulsion[j].account_id==0)
- break;
- }
- // Expulsion list is full, flush the oldest one
- if(j==MAX_GUILDEXPULSION){
- for(j=0;j<MAX_GUILDEXPULSION-1;j++)
- g->expulsion[j]=g->expulsion[j+1];
- j=MAX_GUILDEXPULSION-1;
- }
- // Save the expulsion
- g->expulsion[j].account_id=account_id;
- memcpy(g->expulsion[j].acc,"dummy",NAME_LENGTH-1);
- memcpy(g->expulsion[j].name,g->member[i].name,NAME_LENGTH-1);
- memcpy(g->expulsion[j].mes,mes,40);
- }
-
- mapif_guild_leaved(guild_id,account_id,char_id,flag,g->member[i].name,mes);
- inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id);
-
- memset(&g->member[i],0,sizeof(struct guild_member));
-
- if(!guild_check_empty(g)) {
- break;
- }
- //Guild empty? break it.
- mapif_parse_BreakGuild(-1,guild_id); //Break the guild.
- return 0;
- }
- }
- //Update member info.
- if (!guild_calcinfo(g))
- mapif_guild_info(fd,g);
- g->save_flag |= GS_EXPULSION;
- }else{
- // Unknown guild, just update the player
- sprintf(tmp_sql, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'",char_db, account_id,char_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- /* mapif_guild_leaved(guild_id,account_id,char_id,flag,g->member[i].name,mes); */
- }
-
- return 0;
-}
-
-// Change member info
-int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,
- int account_id,int char_id,int online,int lv,int class_)
-{
- // Could speed up by manipulating only guild_member
- struct guild * g;
- int i,alv,c;
- int prev_count;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- prev_count = g->connect_member;
- g->connect_member=0;
-
- for(i=0,alv=0,c=0;i<g->max_member;i++)
- {
- // Found the member
- if(g->member[i].account_id==account_id && g->member[i].char_id==char_id)
- {
- g->member[i].online=online;
- g->member[i].lv=lv;
- g->member[i].class_=class_;
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfoshort(g,i);
- }
- if( g->member[i].account_id>0 )
- {
- if (g->member[i].lv > 0)
- {
- alv+=g->member[i].lv;
- c++;
- }
- else
- {
- ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv);
- }
- }
- if( g->member[i].online )
- g->connect_member++;
- }
-
- if (c)
- {
- alv = alv/c;
- if (g->connect_member != prev_count || g->average_lv != alv)
- {
- g->average_lv=alv;
- g->save_flag |= GS_CONNECT;
- }
- if (g->save_flag & GS_REMOVE)
- g->save_flag &= ~GS_REMOVE;
- }
- g->save_flag |= GS_MEMBER; //Update guild member data
- return 0;
-}
-
-// BreakGuild
-int mapif_parse_BreakGuild(int fd,int guild_id)
-{
- struct guild * g;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- // Delete guild from sql
- //printf("- Delete guild %d from guild\n",guild_id);
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- //printf("- Update guild %d of char\n",guild_id);
- sprintf(tmp_sql, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'",char_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- mapif_guild_broken(guild_id,0);
-
- if(log_inter)
- inter_log("guild %s (id=%d) broken" RETCODE,g->name,guild_id);
-
- //Remove the guild from memory. [Skotlex]
- idb_remove(guild_db_, guild_id);
- return 0;
-}
-
-// Forward Guild message to others map servers
-int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len)
-{
- return mapif_guild_message(guild_id,account_id,mes,len, fd);
-}
-
-// Modification of the guild
-int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len)
-{
- struct guild * g;
- short dw=*((short *)data);
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- switch(type)
- {
- case GBI_GUILDLV:
- ShowDebug("GBI_GUILDLV\n");
- if(dw>0 && g->guild_lv+dw<=50)
- {
- g->guild_lv+=dw;
- g->skill_point+=dw;
- }
- else if(dw<0 && g->guild_lv+dw>=1)
- g->guild_lv+=dw;
- mapif_guild_info(-1,g);
- g->save_flag |= GS_LEVEL;
- return 0;
- default:
- ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type);
- break;
- }
- mapif_guild_basicinfochanged(guild_id,type,data,len);
- return 0;
-}
-
-// Modification of the guild
-int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,
- int type,const char *data,int len)
-{
- // Could make some improvement in speed, because only change guild_member
- int i;
- struct guild * g;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- // Search the member
- for(i=0;i<g->max_member;i++)
- if( g->member[i].account_id==account_id &&
- g->member[i].char_id==char_id )
- break;
-
- // Not Found
- if(i==g->max_member){
- ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n",
- account_id,char_id,guild_id,g->name);
- return 0;
- }
-
- switch(type)
- {
- case GMI_POSITION:
- {
- g->member[i].position=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER;
- break;
- }
- case GMI_EXP:
- { // EXP
- unsigned int exp, old_exp=g->member[i].exp;
- g->member[i].exp=*((unsigned int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- if (g->member[i].exp > old_exp)
- {
- exp = g->member[i].exp - old_exp;
-
- // Compute gained exp
- if (guild_exp_rate != 100)
- exp = exp*guild_exp_rate/100;
-
- // Update guild exp
- if (exp > UINT_MAX - g->exp)
- g->exp = UINT_MAX;
- else
- g->exp+=exp;
-
- guild_calcinfo(g);
- mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,4);
- g->save_flag |= GS_LEVEL;
- }
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER;
- break;
- }
- case GMI_HAIR:
- {
- g->member[i].hair=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER; //Save new data.
- break;
- }
- case GMI_HAIR_COLOR:
- {
- g->member[i].hair_color=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER; //Save new data.
- break;
- }
- case GMI_GENDER:
- {
- g->member[i].gender=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER; //Save new data.
- break;
- }
- case GMI_CLASS:
- {
- g->member[i].class_=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER; //Save new data.
- break;
- }
- case GMI_LEVEL:
- {
- g->member[i].lv=*((int *)data);
- g->member[i].modified = GS_MEMBER_MODIFIED;
- mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
- g->save_flag |= GS_MEMBER; //Save new data.
- break;
- }
- default:
- ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type);
- break;
- }
- return 0;
-}
-
-int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender)
-{
- return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender));
-}
-
-// Change a position desc
-int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p)
-{
- // Could make some improvement in speed, because only change guild_position
- struct guild * g;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION)
- return 0;
-
- memcpy(&g->position[idx],p,sizeof(struct guild_position));
- mapif_guild_position(g,idx);
- ShowInfo("int_guild: position data changed (Guild %d, position %d)\n",guild_id, idx);
- g->position[idx].modified = GS_POSITION_MODIFIED;
- g->save_flag |= GS_POSITION; // Change guild_position
- return 0;
-}
-
-// Guild Skill UP
-int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id)
-{
- struct guild * g;
- int idx = skill_num - GD_SKILLBASE;
-
- g = inter_guild_fromsql(guild_id);
- if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL)
- return 0;
-
- if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lv<10 )
- {
- g->skill[idx].lv++;
- g->skill_point--;
- if (!guild_calcinfo(g))
- mapif_guild_info(-1,g);
- mapif_guild_skillupack(guild_id,skill_num,account_id);
- g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill
- }
- return 0;
-}
-
-//Manual deletion of an alliance when partnering guild does not exists. [Skotlex]
-static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag)
-{
- int i;
- char name[NAME_LENGTH];
- for(i=0;i<MAX_GUILDALLIANCE;i++)
- if(g->alliance[i].guild_id == guild_id)
- {
- strcpy(name, g->alliance[i].name);
- g->alliance[i].guild_id=0;
- break;
- }
- if (i == MAX_GUILDALLIANCE)
- return -1;
-
- mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name);
- g->save_flag |= GS_ALLIANCE;
- return 0;
-}
-
-// Alliance modification
-int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,
- int account_id1,int account_id2,int flag)
-{
- // Could speed up
- struct guild *g[2];
- int j,i;
- g[0] = inter_guild_fromsql(guild_id1);
- g[1] = inter_guild_fromsql(guild_id2);
-
- if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild.
- return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild.
-
- if(g[0]==NULL || g[1]==NULL)
- return 0;
-
- if(flag&GUILD_ALLIANCE_REMOVE)
- {
- // Remove alliance/opposition, in case of alliance, remove on both side
- for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++)
- {
- for(j=0;j<MAX_GUILDALLIANCE;j++)
- {
- if(g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK))
- {
- g[i]->alliance[j].guild_id=0;
- break;
- }
- }
- }
- }
- else
- {
- // Add alliance, in case of alliance, add on both side
- for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++)
- {
- // Search an empty slot
- for(j=0;j<MAX_GUILDALLIANCE;j++)
- {
- if(g[i]->alliance[j].guild_id==0)
- {
- g[i]->alliance[j].guild_id=g[1-i]->guild_id;
- memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH-1);
- // Set alliance type
- g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK;
- break;
- }
- }
- }
- }
-
- // Send on all map the new alliance/opposition
- mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name);
-
- // Mark the two guild to be saved
- g[0]->save_flag |= GS_ALLIANCE;
- g[1]->save_flag |= GS_ALLIANCE;
- return 0;
-}
-
-// Change guild message
-int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2)
-{
- struct guild *g;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- memcpy(g->mes1,mes1,60);
- memcpy(g->mes2,mes2,120);
- g->save_flag |= GS_MES; //Change mes of guild
- return mapif_guild_notice(g);
-}
-
-int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data)
-{
- struct guild * g;
-
- g = inter_guild_fromsql(guild_id);
- if(g==NULL)
- return 0;
-
- if (len > sizeof(g->emblem_data))
- len = sizeof(g->emblem_data);
-
- memcpy(g->emblem_data,data,len);
- g->emblem_len=len;
- g->emblem_id++;
- g->save_flag |= GS_EMBLEM; //Change guild
- return mapif_guild_emblem(g);
-}
-
-int mapif_parse_GuildCastleDataLoad(int fd,int castle_id,int index) // <Agit>
-{
- struct guild_castle gc;
- if (!inter_guildcastle_fromsql(castle_id, &gc)) {
- return mapif_guild_castle_dataload(castle_id,0,0);
- }
- switch(index){
- case 1: return mapif_guild_castle_dataload(gc.castle_id,index,gc.guild_id); break;
- case 2: return mapif_guild_castle_dataload(gc.castle_id,index,gc.economy); break;
- case 3: return mapif_guild_castle_dataload(gc.castle_id,index,gc.defense); break;
- case 4: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerE); break;
- case 5: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerD); break;
- case 6: return mapif_guild_castle_dataload(gc.castle_id,index,gc.nextTime); break;
- case 7: return mapif_guild_castle_dataload(gc.castle_id,index,gc.payTime); break;
- case 8: return mapif_guild_castle_dataload(gc.castle_id,index,gc.createTime); break;
- case 9: return mapif_guild_castle_dataload(gc.castle_id,index,gc.visibleC); break;
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-10].visible); break;
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25:
- return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-18].hp); break;
- default:
- ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index);
- return 0;
- }
-}
-
-int mapif_parse_GuildCastleDataSave(int fd,int castle_id,int index,int value) // <Agit>
-{
- struct guild_castle gc;
- if(!inter_guildcastle_fromsql(castle_id, &gc))
- return mapif_guild_castle_datasave(castle_id,index,value);
-
- switch(index){
- case 1:
- if( gc.guild_id!=value ){
- int gid=(value)?value:gc.guild_id;
- struct guild *g=idb_get(guild_db_, gid);
- if(log_inter)
- inter_log("guild %s (id=%d) %s castle id=%d" RETCODE,
- (g)?g->name:"??" ,gid, (value)?"occupy":"abandon", castle_id);
- }
- gc.guild_id = value;
- if(gc.guild_id == 0) {
- //Delete guardians.
- memset(&gc.guardian, 0, sizeof(gc.guardian));
- }
- break;
- case 2: gc.economy = value; break;
- case 3: gc.defense = value; break;
- case 4: gc.triggerE = value; break;
- case 5: gc.triggerD = value; break;
- case 6: gc.nextTime = value; break;
- case 7: gc.payTime = value; break;
- case 8: gc.createTime = value; break;
- case 9: gc.visibleC = value; break;
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- gc.guardian[index-10].visible = value; break;
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25:
- gc.guardian[index-18].hp = value; break; // end additions [Valaris]
- default:
- ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index);
- return 0;
- }
- inter_guildcastle_tosql(&gc);
- mapif_guild_castle_datasave(gc.castle_id,index,value);
- return 0;
-}
-
-int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len)
-{
- struct guild * g;
- struct guild_member gm;
- int pos;
-
- g = inter_guild_fromsql(guild_id);
-
- if(g==NULL || len > NAME_LENGTH)
- return 0;
-
- // Find member (name)
- for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++);
-
- if (pos == g->max_member)
- return 0; //Character not found??
-
- // Switch current and old GM
- memcpy(&gm, &g->member[pos], sizeof (struct guild_member));
- memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member));
- memcpy(&g->member[0], &gm, sizeof(struct guild_member));
-
- // Switch positions
- g->member[pos].position = g->member[0].position;
- g->member[pos].modified = GS_MEMBER_MODIFIED;
- g->member[0].position = 0; //Position 0: guild Master.
- g->member[0].modified = GS_MEMBER_MODIFIED;
-
- strncpy(g->master, name, len);
- if (len < NAME_LENGTH)
- g->master[len] = '\0';
-
- ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name);
- g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data.
- return mapif_guild_master_changed(g, pos);
-}
-
-// ƒMƒ‹ƒhƒ`ƒFƒbƒN—v‹
-int mapif_parse_GuildCheck(int fd,int guild_id,int account_id,int char_id)
-{
- // What does this mean? Check if belong to another guild?
- return 0;
-}
-
-// map server ‚©‚η‚̒ʐM
-// E‚PƒpƒPƒbƒg‚Μ‚έ‰πΝ‚·‚ι‚±‚Ζ
-// EƒpƒPƒbƒg’·ƒf[ƒ^‚Νinter.c‚ΙƒZƒbƒg‚΅‚Δ‚¨‚­‚±‚Ζ
-// EƒpƒPƒbƒg’·ƒ`ƒFƒbƒN‚βARFIFOSKIP‚ΝŒΔ‚Ρo‚΅Œ³‚ōs‚ν‚κ‚ι‚̂ōs‚Α‚Δ‚Ν‚Θ‚η‚Θ‚’
-// EƒGƒ‰[‚Θ‚η0(false)A‚»‚€‚Ε‚Θ‚’‚Θ‚η1(true)‚π‚©‚¦‚³‚Θ‚―‚κ‚Ξ‚Θ‚η‚Θ‚’
-int inter_guild_parse_frommap(int fd)
-{
- RFIFOHEAD(fd);
- switch(RFIFOW(fd,0)){
- case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break;
- case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break;
- case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break;
- case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break;
- case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break;
- case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break;
- case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break;
- case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break;
- case 0x3038: mapif_parse_GuildCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
- case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break;
- case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break;
- case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break;
- case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); break;
- case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break;
- case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break;
- case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break;
- case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),RFIFOB(fd,4)); break;
- case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-int inter_guild_mapif_init(int fd)
-{
- return mapif_guild_castle_alldataload(fd);
-}
-
-// ƒT[ƒo[‚©‚η’E‘ή—v‹iƒLƒƒƒ‰νœ—pj
-int inter_guild_leave(int guild_id,int account_id,int char_id)
-{
- return mapif_parse_GuildLeave(-1,guild_id,account_id,char_id,0,"** Character Deleted **");
-}
-
-int inter_guild_broken(int guild_id)
-{
- return mapif_guild_broken(guild_id, 0);
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by hack
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "char.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+// #include "int_storage.h"
+#include "inter.h"
+#include "int_guild.h"
+#include "mmo.h"
+#include "socket.h"
+#include "db.h"
+#include "malloc.h"
+
+#define GS_MEMBER_UNMODIFIED 0x00
+#define GS_MEMBER_MODIFIED 0x01
+#define GS_MEMBER_NEW 0x02
+
+#define GS_POSITION_UNMODIFIED 0x00
+#define GS_POSITION_MODIFIED 0x01
+
+// LSB = 0 => Alliance, LSB = 1 => Opposition
+#define GUILD_ALLIANCE_TYPE_MASK 0x01
+#define GUILD_ALLIANCE_REMOVE 0x08
+
+static char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+#ifndef TXT_SQL_CONVERT
+//Guild cache
+static struct dbt *guild_db_;
+
+struct guild_castle castles[MAX_GUILDCASTLE];
+
+static unsigned int guild_exp[100];
+
+int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes);
+int mapif_guild_broken(int guild_id,int flag);
+int guild_check_empty(struct guild *g);
+int guild_calcinfo(struct guild *g);
+int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len);
+int mapif_guild_info(int fd,struct guild *g);
+int guild_break_sub(int key,void *data,va_list ap);
+int inter_guild_tosql(struct guild *g,int flag);
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+static int guild_save(DBKey key, void *data, va_list ap) {
+ struct guild *g = (struct guild*) data;
+ int *last_id = va_arg(ap, int *);
+ int *state = va_arg(ap, int *);
+
+ if ((*state) == 0 && g->guild_id == (*last_id))
+ (*state)++; //Save next guild in the list.
+ else if (g->save_flag&GS_MASK && (*state) == 1) {
+ inter_guild_tosql(g, g->save_flag&GS_MASK);
+ g->save_flag &= ~GS_MASK;
+
+ //Some guild saved.
+ (*last_id) = g->guild_id;
+ (*state)++;
+ }
+
+ if(g->save_flag == GS_REMOVE) { //Nothing to save, guild is ready for removal.
+ if (save_log)
+ ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name);
+ db_remove(guild_db_, key);
+ }
+ return 0;
+}
+
+static int guild_save_timer(int tid, unsigned int tick, int id, int data) {
+ static int last_id = 0; //To know in which guild we were.
+ int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving.
+ if (!last_id) //Save the first guild in the list.
+ state = 1;
+ guild_db_->foreach(guild_db_, guild_save, &last_id, &state);
+ if (state != 2) //Reached the end of the guild db without saving.
+ last_id = 0; //Reset guild saved, return to beginning.
+
+ state = guild_db_->size(guild_db_);
+ if (state < 1) state = 1; //Calculate the time slot for the next save.
+ add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0);
+ return 0;
+}
+
+int inter_guild_removemember_tosql(int account_id, int char_id)
+{
+ sprintf(tmp_sql,"DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql,"UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return 0;
+}
+#endif //TXT_SQL_CONVERT
+// Save guild into sql
+int inter_guild_tosql(struct guild *g,int flag)
+{
+ // Table guild (GS_BASIC_MASK)
+ // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data`
+ // GS_CONNECT `connect_member`,`average_lv`
+ // GS_MES `mes1`,`mes2`
+ // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point`
+ // GS_BASIC `name`,`master`,`char_id`
+
+ // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`rsv1`,`rsv2`,`name`)
+ // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`)
+ // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`)
+ // GS_EXPULSION `guild_expulsion` (`guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3`)
+ // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`)
+
+ // temporary storage for str convertion. They must be twice the size of the
+ // original string to ensure no overflows will occur. [Skotlex]
+ char t_name[NAME_LENGTH*2],
+ t_master[NAME_LENGTH*2],
+ t_mes1[120],
+ t_mes2[240],
+ t_member[NAME_LENGTH*2],
+ t_position[NAME_LENGTH*2],
+ t_alliance[NAME_LENGTH*2],
+ t_ename[NAME_LENGTH*2],
+ t_emes[80],
+ t_info[240];
+ char emblem_data[4096];
+ char new_guild = 0;
+ int i=0, sql_index;
+
+ if (g->guild_id<=0 && g->guild_id != -1) return 0;
+
+#ifdef NOISY
+ ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag);
+#endif
+
+ jstrescapecpy(t_name, g->name);
+
+ t_info[0]='\0';
+
+#ifndef TXT_SQL_CONVERT
+ // Insert a new guild the guild
+ if (flag&GS_BASIC && g->guild_id == -1)
+ {
+ strcat(t_info, " guild_create");
+
+ // Create a new guild
+ sprintf(tmp_sql,"INSERT INTO `%s` "
+ "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) "
+ "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')",
+ guild_db,t_name,jstrescapecpy(t_master,g->master),g->guild_lv,g->max_member,g->average_lv,g->member[0].char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) )
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ if (g->guild_id == -1)
+ return 0; //Failed to create guild!
+ }
+ else
+ {
+ //New guild, catch id
+ if(mysql_field_count(&mysql_handle) == 0 && mysql_insert_id(&mysql_handle) != 0)
+ {
+ g->guild_id = (int)mysql_insert_id(&mysql_handle);
+ new_guild = 1;
+ }
+ else
+ return 0; //Failed to get ID??
+ }
+ }
+#else
+ // Insert a new guild the guild
+ if (flag&GS_BASIC)
+ {
+ strcat(t_info, " guild_create");
+ // Since the PK is guild id + master id, a replace will not be enough if we are overwriting data, we need to wipe the previous guild.
+ sprintf(tmp_sql,"DELETE FROM `%s` where `guild_id` = '%d'", guild_db,g->guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) )
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ // Create a new guild
+ sprintf(tmp_sql,"REPLACE INTO `%s` "
+ "(`guild_id`,`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) "
+ "VALUES ('%d', '%s', '%s', '%d', '%d', '%d', '%d')",
+ guild_db,g->guild_id,t_name,jstrescapecpy(t_master,g->master),g->guild_lv,g->max_member,g->average_lv,g->member[0].char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) )
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0; //Failed to create guild.
+ }
+ }
+#endif //TXT_SQL_CONVERT
+ // If we need an update on an existing guild or more update on the new guild
+ if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild))
+ {
+ sql_index = sprintf(tmp_sql,"UPDATE `%s` SET ", guild_db);
+
+ if (flag & GS_EMBLEM)
+ {
+ char * pData = emblem_data;
+ strcat(t_info, " emblem");
+ // Convert emblem_data to hex
+ for(i=0; i<g->emblem_len; i++){
+ *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F];
+ *pData++ = dataToHex[g->emblem_data[i] & 0x0F];
+ }
+ *pData = 0;
+ sql_index += sprintf(tmp_sql + sql_index,"`emblem_len`=%d,`emblem_id`=%d,`emblem_data`='%s',",g->emblem_len,g->emblem_id,emblem_data);
+ }
+ if (flag & GS_BASIC)
+ {
+ strcat(t_info, " basic");
+ sql_index += sprintf(tmp_sql + sql_index,"`name`='%s', `master`='%s', `char_id`=%d,",t_name,jstrescapecpy(t_master,g->master),g->member[0].char_id);
+ }
+ if (flag & GS_CONNECT)
+ {
+ strcat(t_info, " connect");
+ sql_index += sprintf(tmp_sql + sql_index,"`connect_member`=%d,`average_lv`=%d,",g->connect_member, g->average_lv);
+ }
+ if (flag & GS_MES)
+ {
+ strcat(t_info, " mes");
+ sql_index += sprintf(tmp_sql + sql_index,"`mes1`='%s',`mes2`='%s',",jstrescapecpy(t_mes1,g->mes1),jstrescapecpy(t_mes2,g->mes2));
+ }
+ if (flag & GS_LEVEL)
+ {
+ strcat(t_info, " level");
+ sql_index += sprintf(tmp_sql + sql_index,"`guild_lv`=%d,`skill_point`=%d,`exp`=%u,`next_exp`=%u,`max_member`=%d,",g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member);
+ }
+ sprintf(tmp_sql + sql_index -1," WHERE `guild_id`=%d", g->guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ if (flag&GS_MEMBER)
+ {
+ struct guild_member *m;
+ strcat(t_info, " members");
+ // Update only needed players
+ for(i=0;i<g->max_member;i++){
+ m = &g->member[i];
+#ifndef TXT_SQL_CONVERT
+ if (!m->modified)
+ continue;
+#endif
+ if(m->account_id) {
+ //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO
+ sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) "
+ "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%u','%d','%d','%d','%s')",
+ guild_member_db, g->guild_id, m->account_id,m->char_id,
+ m->hair,m->hair_color,m->gender,
+ m->class_,m->lv,m->exp,m->exp_payper,m->online,m->position,
+ jstrescapecpy(t_member,m->name));
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ if (m->modified & GS_MEMBER_NEW)
+ {
+ sprintf(tmp_sql,"UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'",
+ char_db, g->guild_id, m->char_id);
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ m->modified = GS_MEMBER_UNMODIFIED;
+ }
+ }
+ }
+
+ if (flag&GS_POSITION){
+ strcat(t_info, " positions");
+ //printf("- Insert guild %d to guild_position\n",g->guild_id);
+ for(i=0;i<MAX_GUILDPOSITION;i++){
+ struct guild_position *p = &g->position[i];
+#ifndef TXT_SQL_CONVERT
+ if (!p->modified)
+ continue;
+#endif
+ sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d', '%s','%d','%d')",
+ guild_position_db, g->guild_id, i, jstrescapecpy(t_position,p->name),p->mode,p->exp_mode);
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ p->modified = GS_POSITION_UNMODIFIED;
+ }
+ }
+
+ if (flag&GS_ALLIANCE)
+ {
+ // Delete current alliances
+ // NOTE: no need to do it on both sides since both guilds in memory had
+ // their info changed, not to mention this would also mess up oppositions!
+ // [Skotlex]
+// sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'",guild_alliance_db, g->guild_id,g->guild_id);
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_alliance_db, g->guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) )
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ else
+ {
+ //printf("- Insert guild %d to guild_alliance\n",g->guild_id);
+ for(i=0;i<MAX_GUILDALLIANCE;i++)
+ {
+ struct guild_alliance *a=&g->alliance[i];
+ if(a->guild_id>0)
+ {
+ sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) "
+ "VALUES ('%d','%d','%d','%s')",
+ guild_alliance_db, g->guild_id,a->opposition,a->guild_id,jstrescapecpy(t_alliance,a->name));
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) )
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ }
+ }
+
+ if (flag&GS_EXPULSION){
+ strcat(t_info, " expulsions");
+ //printf("- Insert guild %d to guild_expulsion\n",g->guild_id);
+ for(i=0;i<MAX_GUILDEXPULSION;i++){
+ struct guild_expulsion *e=&g->expulsion[i];
+ if(e->account_id>0){
+ sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3`) "
+ "VALUES ('%d','%s','%s','%s','%d','%d','%d','%d')",
+ guild_expulsion_db, g->guild_id,
+ jstrescapecpy(t_ename,e->name),jstrescapecpy(t_emes,e->mes),e->acc,e->account_id,e->rsv1,e->rsv2,e->rsv3 );
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ }
+
+ if (flag&GS_SKILL){
+ strcat(t_info, " skills");
+ //printf("- Insert guild %d to guild_skill\n",g->guild_id);
+ for(i=0;i<MAX_GUILDSKILL;i++){
+ if (g->skill[i].id>0 && g->skill[i].lv>0){
+ sprintf(tmp_sql,"REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')",
+ guild_skill_db, g->guild_id,g->skill[i].id,g->skill[i].lv);
+ //printf("%s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ }
+
+ if (save_log)
+ ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info);
+ return 1;
+}
+#ifndef TXT_SQL_CONVERT
+// Read guild from sql
+struct guild * inter_guild_fromsql(int guild_id)
+{
+ int i;
+ char * pstr, * pEmblemData;
+ struct guild *g;
+
+ if (guild_id<=0) return NULL;
+
+ g = idb_get(guild_db_,guild_id);
+ if (g) return g;
+
+ g = (struct guild*)aCalloc(sizeof(struct guild), 1);
+
+#ifdef NOISY
+ ShowInfo("Guild load request (%d)...\n", guild_id);
+#endif
+
+ sprintf(tmp_sql,"SELECT `name`,`master`,`guild_lv`,`connect_member`,`max_member`,`average_lv`,`exp`,`next_exp`,`skill_point`,`mes1`,`mes2`,`emblem_len`,`emblem_id`,`emblem_data` "
+ "FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res==NULL || mysql_num_rows(sql_res)<1) {
+ //Guild does not exists.
+ if (sql_res) mysql_free_result(sql_res);
+ aFree(g);
+ return NULL;
+ }
+
+ sql_row = mysql_fetch_row(sql_res);
+ if (sql_row==NULL) {
+ mysql_free_result(sql_res);
+ aFree(g);
+ return NULL;
+ }
+
+ g->guild_id=guild_id;
+ strncpy(g->name,sql_row[0],NAME_LENGTH-1);
+ strncpy(g->master,sql_row[1],NAME_LENGTH-1);
+ g->guild_lv=atoi(sql_row[2]);
+ g->connect_member=atoi(sql_row[3]);
+ g->max_member = atoi(sql_row[4]);
+ if (g->max_member > MAX_GUILD)
+ { // Fix reduction of MAX_GUILD [PoW]
+ ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD);
+ g->max_member = MAX_GUILD;
+ }
+ g->average_lv=atoi(sql_row[5]);
+ g->exp=(unsigned int)atof(sql_row[6]);
+ g->next_exp=(unsigned int)atof(sql_row[7]);
+ g->skill_point=atoi(sql_row[8]);
+ //There shouldn't be a need to copy the very last char, as it's the \0 [Skotlex]
+ strncpy(g->mes1,sql_row[9],59);
+ strncpy(g->mes2,sql_row[10],119);
+ g->emblem_len=atoi(sql_row[11]);
+ g->emblem_id=atoi(sql_row[12]);
+ for(i=0,pstr=sql_row[13],pEmblemData=g->emblem_data; i < g->emblem_len; i++,pstr+=2){
+ int c1=pstr[0],c2=pstr[1],x1=0,x2=0;
+ if(c1>='0' && c1<='9')
+ x1=c1-'0';
+ else if(c1>='a' && c1<='f')
+ x1=c1-'a'+10;
+ else if(c1>='A' && c1<='F')
+ x1=c1-'A'+10;
+ if(c2>='0' && c2<='9')
+ x2=c2-'0';
+ else if(c2>='a' && c2<='f')
+ x2=c2-'a'+10;
+ else if(c2>='A' && c2<='F')
+ x2=c2-'A'+10;
+ *pEmblemData++=(x1<<4)|x2;
+ }
+ mysql_free_result(sql_res);
+
+ //printf("- Read guild_member %d from sql \n",guild_id);
+ sprintf(tmp_sql,"SELECT `guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`rsv1`,`rsv2`,`name` "
+ "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id);
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res) {
+ for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<g->max_member);i++){
+ struct guild_member *m = &g->member[i];
+ m->account_id=atoi(sql_row[1]);
+ m->char_id=atoi(sql_row[2]);
+ m->hair=atoi(sql_row[3]);
+ m->hair_color=atoi(sql_row[4]);
+ m->gender=atoi(sql_row[5]);
+ m->class_=atoi(sql_row[6]);
+ m->lv=atoi(sql_row[7]);
+ m->exp=strtoul(sql_row[8],NULL,10);
+ m->exp_payper=atoi(sql_row[9]);
+ m->online=atoi(sql_row[10]);
+ m->position = atoi(sql_row[11]);
+ if (m->position >= MAX_GUILDPOSITION) // Fix reduction of MAX_GUILDPOSITION [PoW]
+ m->position = MAX_GUILDPOSITION - 1;
+
+ strncpy(m->name,sql_row[14],NAME_LENGTH-1);
+ m->modified = GS_MEMBER_UNMODIFIED;
+ }
+ mysql_free_result(sql_res);
+ }
+
+ //printf("- Read guild_position %d from sql \n",guild_id);
+ sprintf(tmp_sql,"SELECT `guild_id`,`position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'",guild_position_db, guild_id);
+ //printf(" %s\n",tmp_sql);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res) {
+ for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDPOSITION);i++){
+ int position = atoi(sql_row[1]);
+ struct guild_position *p = &g->position[position];
+ strncpy(p->name,sql_row[2],NAME_LENGTH-1);
+ p->mode=atoi(sql_row[3]);
+ p->exp_mode=atoi(sql_row[4]);
+ p->modified = GS_POSITION_UNMODIFIED;
+ }
+ mysql_free_result(sql_res);
+ }
+
+ //printf("- Read guild_alliance %d from sql \n",guild_id);
+ sprintf(tmp_sql,"SELECT `guild_id`,`opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'",guild_alliance_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res) {
+ for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDALLIANCE);i++){
+ struct guild_alliance *a = &g->alliance[i];
+ a->opposition=atoi(sql_row[1]);
+ a->guild_id=atoi(sql_row[2]);
+ strncpy(a->name,sql_row[3],NAME_LENGTH-1);
+ }
+ mysql_free_result(sql_res);
+ }
+
+ //printf("- Read guild_expulsion %d from sql \n",guild_id);
+ sprintf(tmp_sql,"SELECT `guild_id`,`name`,`mes`,`acc`,`account_id`,`rsv1`,`rsv2`,`rsv3` FROM `%s` WHERE `guild_id`='%d'",guild_expulsion_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res) {
+ for(i=0;((sql_row = mysql_fetch_row(sql_res))&&i<MAX_GUILDEXPULSION);i++){
+ struct guild_expulsion *e = &g->expulsion[i];
+
+ strncpy(e->name,sql_row[1],NAME_LENGTH-1);
+ //No need to copy char 40, the null terminator. [Skotlex]
+ strncpy(e->mes,sql_row[2],39);
+ strncpy(e->acc,sql_row[3],39);
+ e->account_id=atoi(sql_row[4]);
+ e->rsv1=atoi(sql_row[5]);
+ e->rsv2=atoi(sql_row[6]);
+ e->rsv3=atoi(sql_row[7]);
+ }
+ mysql_free_result(sql_res);
+ }
+
+ //printf("- Read guild_skill %d from sql \n",guild_id);
+ sprintf(tmp_sql,"SELECT `guild_id`,`id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`",guild_skill_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ aFree(g);
+ return NULL;
+ }
+
+ for(i = 0; i < MAX_GUILDSKILL; i++)
+ { //Skill IDs must always be initialized. [Skotlex]
+ g->skill[i].id = i + GD_SKILLBASE;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res) {
+ while ((sql_row = mysql_fetch_row(sql_res))){
+ int id = atoi(sql_row[1])-GD_SKILLBASE;
+ if (id >= 0 && id < MAX_GUILDSKILL)
+ //I know this seems ridiculous, but the skills HAVE to be placed on their 'correct' array slot or things break x.x [Skotlex]
+ g->skill[id].lv=atoi(sql_row[2]);
+ }
+ mysql_free_result(sql_res);
+ }
+
+ idb_put(guild_db_, guild_id, g); //Add to cache
+ g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long.
+
+ if (save_log)
+ ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name);
+
+ return g;
+}
+
+#endif //TXT_SQL_CONVERT
+int inter_guildcastle_tosql(struct guild_castle *gc){
+ // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`)
+
+ if (gc==NULL) return 0;
+ #ifdef GUILD_DEBUG
+ShowDebug("Save guild_castle (%d)\n", gc->castle_id);
+ #endif
+
+// sql_query("DELETE FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, gc->castle_id);
+
+ sprintf(tmp_sql,"REPLACE INTO `%s` "
+ "(`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`,"
+ "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`,"
+ "`Ghp0`, `Ghp1`, `Ghp2`, `Ghp3`, `Ghp4`, `Ghp5`, `Ghp6`, `Ghp7`)"
+ "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d')",
+ guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime,
+ gc->createTime, gc->visibleC,
+ gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible,
+ gc->guardian[0].hp, gc->guardian[1].hp, gc->guardian[2].hp, gc->guardian[3].hp, gc->guardian[4].hp, gc->guardian[5].hp, gc->guardian[6].hp, gc->guardian[7].hp);
+
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+#ifndef TXT_SQL_CONVERT
+ memcpy(&castles[gc->castle_id],gc,sizeof(struct guild_castle));
+#endif //TXT_SQL_CONVERT
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+
+// Read guild_castle from sql
+int inter_guildcastle_fromsql(int castle_id,struct guild_castle *gc)
+{
+ static int castles_init=0;
+ if (gc==NULL) return 0;
+ if (castle_id==-1) return 0;
+
+ if(!castles_init)
+ {
+ int i;
+ for(i=0;i<MAX_GUILDCASTLE;i++)
+ castles[i].castle_id=-1;
+ castles_init = 1;
+ }
+
+ if(castles[castle_id].castle_id == castle_id)
+ {
+ memcpy(gc,&castles[castle_id],sizeof(struct guild_castle));
+ return 1;
+ }
+
+ memset(gc,0,sizeof(struct guild_castle));
+ sprintf(tmp_sql,"SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, "
+ "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`,"
+ "`Ghp0`, `Ghp1`, `Ghp2`, `Ghp3`, `Ghp4`, `Ghp5`, `Ghp6`, `Ghp7`"
+ " FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, castle_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ // ARU: This needs to be set even if there are no SQL results
+ gc->castle_id=castle_id;
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+ if (sql_row==NULL){
+ mysql_free_result(sql_res);
+ return 1; //Assume empty castle.
+ }
+ gc->guild_id = atoi (sql_row[1]);
+ gc->economy = atoi (sql_row[2]);
+ gc->defense = atoi (sql_row[3]);
+ gc->triggerE = atoi (sql_row[4]);
+ gc->triggerD = atoi (sql_row[5]);
+ gc->nextTime = atoi (sql_row[6]);
+ gc->payTime = atoi (sql_row[7]);
+ gc->createTime = atoi (sql_row[8]);
+ gc->visibleC = atoi (sql_row[9]);
+ gc->guardian[0].visible = atoi (sql_row[10]);
+ gc->guardian[1].visible = atoi (sql_row[11]);
+ gc->guardian[2].visible = atoi (sql_row[12]);
+ gc->guardian[3].visible = atoi (sql_row[13]);
+ gc->guardian[4].visible = atoi (sql_row[14]);
+ gc->guardian[5].visible = atoi (sql_row[15]);
+ gc->guardian[6].visible = atoi (sql_row[16]);
+ gc->guardian[7].visible = atoi (sql_row[17]);
+ gc->guardian[0].hp = atoi (sql_row[18]);
+ gc->guardian[1].hp = atoi (sql_row[19]);
+ gc->guardian[2].hp = atoi (sql_row[20]);
+ gc->guardian[3].hp = atoi (sql_row[21]);
+ gc->guardian[4].hp = atoi (sql_row[22]);
+ gc->guardian[5].hp = atoi (sql_row[23]);
+ gc->guardian[6].hp = atoi (sql_row[24]);
+ gc->guardian[7].hp = atoi (sql_row[25]);
+
+ if (save_log)
+ ShowInfo("Loaded Castle %d (guild %d)\n",castle_id,gc->guild_id);
+
+ }
+ mysql_free_result(sql_res) ; //resource free
+
+ memcpy(&castles[castle_id],gc,sizeof(struct guild_castle));
+
+ return 1;
+}
+
+
+// Read exp_guild.txt
+int inter_guild_ReadEXP(void)
+{
+ int i;
+ FILE *fp;
+ char line[1024];
+ for (i=0;i<100;i++) guild_exp[i]=0;
+
+ sprintf(line, "%s/exp_guild.txt", db_path);
+ fp=fopen(line,"r");
+ if(fp==NULL){
+ ShowError("can't read %s\n", line);
+ return 1;
+ }
+ i=0;
+ while(fgets(line,256,fp) && i<100){
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ guild_exp[i]=(unsigned int)atof(line);
+ i++;
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+
+int inter_guild_CharOnline(int char_id, int guild_id) {
+
+ struct guild *g;
+ int i;
+
+ if (guild_id == -1) {
+ //Get guild_id from the database
+ sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if(sql_res == NULL)
+ return 0; //Eh? No guild?
+
+ sql_row = mysql_fetch_row(sql_res);
+ guild_id = sql_row?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+ }
+ if (guild_id == 0)
+ return 0; //No guild...
+
+ g = inter_guild_fromsql(guild_id);
+ if(!g) {
+ ShowError("Character %d's guild %d not found!\n", char_id, guild_id);
+ return 0;
+ }
+
+ //Member has logged in before saving, tell saver not to delete
+ if(g->save_flag & GS_REMOVE)
+ g->save_flag &= ~GS_REMOVE;
+
+ //Set member online
+ for(i=0; i<g->max_member; i++) {
+ if (g->member[i].char_id == char_id) {
+ g->member[i].online = 1;
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ break;
+ }
+ }
+ return 1;
+}
+
+int inter_guild_CharOffline(int char_id, int guild_id) {
+ struct guild *g=NULL;
+ int online_count=0, i;
+
+ if (guild_id == -1) {
+ //Get guild_id from the database
+ sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if(sql_res == NULL)
+ return 0; //Eh? No guild?
+
+ sql_row = mysql_fetch_row(sql_res);
+ guild_id = sql_row?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+ }
+ if (guild_id == 0)
+ return 0; //No guild...
+
+ //Character has a guild, set character offline and check if they were the only member online
+ g = inter_guild_fromsql(guild_id);
+ if (g == NULL) //Guild not found?
+ return 0;
+
+ //Set member offline
+ for(i=0; i<g->max_member; i++) {
+ if(g->member[i].char_id == char_id)
+ {
+ g->member[i].online = 0;
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ }
+ if(g->member[i].online && !online_count)
+ online_count++;
+ }
+
+ // Remove guild from memory if no players online
+ if(online_count == 0)
+ g->save_flag |= GS_REMOVE;
+
+ return 1;
+}
+
+// Initialize guild sql
+int inter_guild_sql_init(void)
+{
+ //Initialize the guild cache
+ guild_db_= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+
+ //Read exp file
+ inter_guild_ReadEXP();
+
+ add_timer_func_list(guild_save_timer, "guild_save_timer");
+ add_timer(gettick() + 10000, guild_save_timer, 0, 0);
+ return 0;
+}
+
+static int guild_db_final(DBKey key, void *data, va_list ap)
+{
+ struct guild *g = (struct guild*)data;
+ if (g->save_flag&GS_MASK) {
+ inter_guild_tosql(g, g->save_flag&GS_MASK);
+ return 1;
+ }
+ return 0;
+}
+
+void inter_guild_sql_final(void)
+{
+ guild_db_->destroy(guild_db_, guild_db_final);
+ return;
+}
+
+// Get guild_id by its name. Returns 0 if not found, -1 on error.
+int search_guildname(char *str)
+{
+ int guild_id;
+ char t_name[NAME_LENGTH*2];
+
+ jstrescapecpy(t_name, str);
+ //Lookup guilds with the same name
+ sprintf (tmp_sql , "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, t_name);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return -1;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if(sql_res)
+ sql_row = mysql_fetch_row(sql_res);
+
+ guild_id = (sql_row&&sql_res&&sql_row[0])?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+ return guild_id;
+}
+
+// Check if guild is empty
+int guild_check_empty(struct guild *g)
+{
+ int i;
+ for(i=0;i<g->max_member;i++){
+ if(g->member[i].account_id>0){
+ return 0;
+ }
+ }
+ //Let the calling function handle the guild removal in case they need
+ //to do something else with it before freeing the data. [Skotlex]
+ return 1;
+}
+
+unsigned int guild_nextexp(int level)
+{
+ if (level == 0)
+ return 1;
+ if (level < 100 && level > 0) // Change by hack
+ return guild_exp[level-1];
+
+ return 0;
+}
+
+int guild_checkskill(struct guild *g,int id) {
+
+ int idx = id - GD_SKILLBASE;
+
+ if(idx < 0 || idx >= MAX_GUILDSKILL)
+ return 0;
+
+ return g->skill[idx].lv;
+}
+
+int guild_calcinfo(struct guild *g)
+{
+ int i,c;
+ unsigned int nextexp;
+ struct guild before = *g; // Save guild current values
+
+ if(g->guild_lv<=0)
+ g->guild_lv = 1;
+ nextexp = guild_nextexp(g->guild_lv);
+
+ // Consume guild exp and increase guild level
+ while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin]
+ g->exp-=nextexp;
+ g->guild_lv++;
+ g->skill_point++;
+ nextexp = guild_nextexp(g->guild_lv);
+ }
+
+ // Save next exp step
+ g->next_exp = nextexp;
+
+ // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv.
+ g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6;
+ if(g->max_member > MAX_GUILD)
+ {
+ ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD);
+ g->max_member = MAX_GUILD;
+ }
+
+ // Compute the guild average level level
+ g->average_lv=0;
+ g->connect_member=0;
+ for(i=c=0;i<g->max_member;i++)
+ {
+ if(g->member[i].account_id>0)
+ {
+ if (g->member[i].lv >= 0)
+ {
+ g->average_lv+=g->member[i].lv;
+ c++;
+ }
+ else
+ {
+ ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv);
+ }
+
+ if(g->member[i].online)
+ g->connect_member++;
+ }
+ }
+ if(c)
+ g->average_lv /= c;
+
+ // Check if guild stats has change
+ if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point )
+ {
+ g->save_flag |= GS_LEVEL;
+ mapif_guild_info(-1,g);
+ return 1;
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------
+// Packet sent to map server
+
+int mapif_guild_created(int fd,int account_id,struct guild *g)
+{
+ WFIFOHEAD(fd, 10);
+ WFIFOW(fd,0)=0x3830;
+ WFIFOL(fd,2)=account_id;
+ if(g != NULL)
+ {
+ WFIFOL(fd,6)=g->guild_id;
+ ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name);
+ } else
+ WFIFOL(fd,6)=0;
+
+ WFIFOSET(fd,10);
+ return 0;
+}
+// Guild not found
+int mapif_guild_noinfo(int fd,int guild_id)
+{
+ unsigned char buf[12];
+ WBUFW(buf,0)=0x3831;
+ WBUFW(buf,2)=8;
+ WBUFL(buf,4)=guild_id;
+ ShowWarning("int_guild: info not found %d\n",guild_id);
+ if(fd<0)
+ mapif_sendall(buf,8);
+ else
+ mapif_send(fd,buf,8);
+ return 0;
+}
+
+// Send guild info
+int mapif_guild_info(int fd,struct guild *g)
+{
+ unsigned char buf[8+sizeof(struct guild)];
+ WBUFW(buf,0)=0x3831;
+ WBUFW(buf,2)=4+sizeof(struct guild);
+ memcpy(buf+4,g,sizeof(struct guild));
+ if(fd<0)
+ mapif_sendall(buf,WBUFW(buf,2));
+ else
+ mapif_send(fd,buf,WBUFW(buf,2));
+ return 0;
+}
+
+// ACK member add
+int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag)
+{
+ WFIFOHEAD(fd, 15);
+ WFIFOW(fd,0)=0x3832;
+ WFIFOL(fd,2)=guild_id;
+ WFIFOL(fd,6)=account_id;
+ WFIFOL(fd,10)=char_id;
+ WFIFOB(fd,14)=flag;
+ WFIFOSET(fd,15);
+ return 0;
+}
+
+// ACK member leave
+int mapif_guild_leaved(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes)
+{
+ unsigned char buf[55+NAME_LENGTH];
+ WBUFW(buf, 0)=0x3834;
+ WBUFL(buf, 2)=guild_id;
+ WBUFL(buf, 6)=account_id;
+ WBUFL(buf,10)=char_id;
+ WBUFB(buf,14)=flag;
+ memcpy(WBUFP(buf,15),mes,40);
+ memcpy(WBUFP(buf,55),name,NAME_LENGTH);
+ mapif_sendall(buf,55+NAME_LENGTH);
+ ShowInfo("int_guild: guild leaved (%d - %d: %s - %s)\n",guild_id,account_id,name,mes);
+ return 0;
+}
+
+// Send short member's info
+int mapif_guild_memberinfoshort(struct guild *g,int idx)
+{
+ unsigned char buf[19];
+ WBUFW(buf, 0)=0x3835;
+ WBUFL(buf, 2)=g->guild_id;
+ WBUFL(buf, 6)=g->member[idx].account_id;
+ WBUFL(buf,10)=g->member[idx].char_id;
+ WBUFB(buf,14)=(unsigned char)g->member[idx].online;
+ WBUFW(buf,15)=g->member[idx].lv;
+ WBUFW(buf,17)=g->member[idx].class_;
+ mapif_sendall(buf,19);
+ return 0;
+}
+
+// Send guild broken
+int mapif_guild_broken(int guild_id,int flag)
+{
+ unsigned char buf[7];
+ WBUFW(buf,0)=0x3836;
+ WBUFL(buf,2)=guild_id;
+ WBUFB(buf,6)=flag;
+ mapif_sendall(buf,7);
+ ShowInfo("int_guild: Guild broken (%d)\n",guild_id);
+ return 0;
+}
+
+// Send guild message
+int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd)
+{
+ unsigned char buf[512];
+ if (len > 500)
+ len = 500;
+ WBUFW(buf,0)=0x3837;
+ WBUFW(buf,2)=len+12;
+ WBUFL(buf,4)=guild_id;
+ WBUFL(buf,8)=account_id;
+ memcpy(WBUFP(buf,12),mes,len);
+ mapif_sendallwos(sfd, buf,len+12);
+ return 0;
+}
+
+// Send basic info
+int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len)
+{
+ unsigned char buf[2048];
+ if (len > 2038)
+ len = 2038;
+ WBUFW(buf, 0)=0x3839;
+ WBUFW(buf, 2)=len+10;
+ WBUFL(buf, 4)=guild_id;
+ WBUFW(buf, 8)=type;
+ memcpy(WBUFP(buf,10),data,len);
+ mapif_sendall(buf,len+10);
+ return 0;
+}
+
+// Send member info
+int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len)
+{
+ unsigned char buf[2048];
+ if (len > 2030)
+ len = 2030;
+ WBUFW(buf, 0)=0x383a;
+ WBUFW(buf, 2)=len+18;
+ WBUFL(buf, 4)=guild_id;
+ WBUFL(buf, 8)=account_id;
+ WBUFL(buf,12)=char_id;
+ WBUFW(buf,16)=type;
+ memcpy(WBUFP(buf,18),data,len);
+ mapif_sendall(buf,len+18);
+ return 0;
+}
+
+// ACK guild skill up
+int mapif_guild_skillupack(int guild_id,int skill_num,int account_id)
+{
+ unsigned char buf[14];
+ WBUFW(buf, 0)=0x383c;
+ WBUFL(buf, 2)=guild_id;
+ WBUFL(buf, 6)=skill_num;
+ WBUFL(buf,10)=account_id;
+ mapif_sendall(buf,14);
+ return 0;
+}
+
+// ACK guild alliance
+int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,
+ int flag,const char *name1,const char *name2)
+{
+ unsigned char buf[19+2*NAME_LENGTH];
+ WBUFW(buf, 0)=0x383d;
+ WBUFL(buf, 2)=guild_id1;
+ WBUFL(buf, 6)=guild_id2;
+ WBUFL(buf,10)=account_id1;
+ WBUFL(buf,14)=account_id2;
+ WBUFB(buf,18)=flag;
+ memcpy(WBUFP(buf,19),name1,NAME_LENGTH);
+ memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH);
+ mapif_sendall(buf,19+2*NAME_LENGTH);
+ return 0;
+}
+
+// Send a guild position desc
+int mapif_guild_position(struct guild *g,int idx)
+{
+ unsigned char buf[12 + sizeof(struct guild_position)];
+ WBUFW(buf,0)=0x383b;
+ WBUFW(buf,2)=sizeof(struct guild_position)+12;
+ WBUFL(buf,4)=g->guild_id;
+ WBUFL(buf,8)=idx;
+ memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position));
+ mapif_sendall(buf,WBUFW(buf,2));
+ return 0;
+}
+
+// Send the guild notice
+int mapif_guild_notice(struct guild *g)
+{
+ unsigned char buf[256];
+ WBUFW(buf,0)=0x383e;
+ WBUFL(buf,2)=g->guild_id;
+ memcpy(WBUFP(buf,6),g->mes1,60);
+ memcpy(WBUFP(buf,66),g->mes2,120);
+ mapif_sendall(buf,186);
+ return 0;
+}
+
+// Send emblem data
+int mapif_guild_emblem(struct guild *g)
+{
+ unsigned char buf[12 + sizeof(g->emblem_data)];
+ WBUFW(buf,0)=0x383f;
+ WBUFW(buf,2)=g->emblem_len+12;
+ WBUFL(buf,4)=g->guild_id;
+ WBUFL(buf,8)=g->emblem_id;
+ memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len);
+ mapif_sendall(buf,WBUFW(buf,2));
+ return 0;
+}
+
+int mapif_guild_master_changed(struct guild *g, int position)
+{
+ unsigned char buf[10];
+ WBUFW(buf,0)=0x3843;
+ WBUFL(buf,2)=g->guild_id;
+ WBUFL(buf,6)=position;
+ mapif_sendall(buf,10);
+ return 0;
+}
+
+int mapif_guild_castle_dataload(int castle_id,int index,int value) // <Agit>
+{
+ unsigned char buf[9];
+ WBUFW(buf, 0)=0x3840;
+ WBUFW(buf, 2)=castle_id;
+ WBUFB(buf, 4)=index;
+ WBUFL(buf, 5)=value;
+ mapif_sendall(buf,9);
+ return 0;
+}
+
+int mapif_guild_castle_datasave(int castle_id,int index,int value) // <Agit>
+{
+ unsigned char buf[9];
+ WBUFW(buf, 0)=0x3841;
+ WBUFW(buf, 2)=castle_id;
+ WBUFB(buf, 4)=index;
+ WBUFL(buf, 5)=value;
+ mapif_sendall(buf,9);
+ return 0;
+}
+
+int mapif_guild_castle_alldataload(int fd) {
+ struct guild_castle* gc = (struct guild_castle *)aMalloc(sizeof(struct guild_castle));
+ int i, len = 4;
+ WFIFOHEAD(fd, len + MAX_GUILDCASTLE*sizeof(struct guild_castle));
+ WFIFOW(fd,0) = 0x3842;
+ sprintf(tmp_sql,"SELECT * FROM `%s` ORDER BY `castle_id`", guild_castle_db);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ for(i = 0; ((sql_row = mysql_fetch_row(sql_res)) && i < MAX_GUILDCASTLE); i++) {
+ memset(gc, 0, sizeof(struct guild_castle));
+ gc->castle_id = atoi(sql_row[0]);
+ gc->guild_id = atoi(sql_row[1]);
+ gc->economy = atoi(sql_row[2]);
+ gc->defense = atoi(sql_row[3]);
+ gc->triggerE = atoi(sql_row[4]);
+ gc->triggerD = atoi(sql_row[5]);
+ gc->nextTime = atoi(sql_row[6]);
+ gc->payTime = atoi(sql_row[7]);
+ gc->createTime = atoi(sql_row[8]);
+ gc->visibleC = atoi(sql_row[9]);
+ gc->guardian[0].visible = atoi(sql_row[10]);
+ gc->guardian[1].visible = atoi(sql_row[11]);
+ gc->guardian[2].visible = atoi(sql_row[12]);
+ gc->guardian[3].visible = atoi(sql_row[13]);
+ gc->guardian[4].visible = atoi(sql_row[14]);
+ gc->guardian[5].visible = atoi(sql_row[15]);
+ gc->guardian[6].visible = atoi(sql_row[16]);
+ gc->guardian[7].visible = atoi(sql_row[17]);
+ gc->guardian[0].visible = atoi(sql_row[18]);
+ gc->guardian[1].visible = atoi(sql_row[19]);
+ gc->guardian[2].visible = atoi(sql_row[20]);
+ gc->guardian[3].visible = atoi(sql_row[21]);
+ gc->guardian[4].visible = atoi(sql_row[22]);
+ gc->guardian[5].visible = atoi(sql_row[23]);
+ gc->guardian[6].visible = atoi(sql_row[24]);
+ gc->guardian[7].visible = atoi(sql_row[25]);
+ memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle));
+ len += sizeof(struct guild_castle);
+ }
+ mysql_free_result(sql_res);
+ }
+ WFIFOW(fd,2) = len;
+ WFIFOSET(fd,len);
+
+ aFree(gc);
+
+ return 0;
+}
+
+
+//-------------------------------------------------------------------
+// Packet received from map server
+
+
+// ƒMƒ‹ƒhμ¬—v‹
+int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master)
+{
+ struct guild *g;
+ int i=0;
+#ifdef NOISY
+ ShowInfo("Creating Guild (%s)\n", name);
+#endif
+ if(search_guildname(name) != 0){
+ ShowInfo("int_guild: guild with same name exists [%s]\n",name);
+ mapif_guild_created(fd,account_id,NULL);
+ return 0;
+ }
+ // Check Authorised letters/symbols in the name of the character
+ if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+ for (i = 0; i < NAME_LENGTH && name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL) {
+ mapif_guild_created(fd,account_id,NULL);
+ return 0;
+ }
+ } else if (char_name_option == 2) { // 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) {
+ mapif_guild_created(fd,account_id,NULL);
+ return 0;
+ }
+ }
+
+ g = (struct guild *)aMalloc(sizeof(struct guild));
+ memset(g,0,sizeof(struct guild));
+
+ memcpy(g->name,name,NAME_LENGTH);
+ memcpy(g->master,master->name,NAME_LENGTH);
+ memcpy(&g->member[0],master,sizeof(struct guild_member));
+ g->member[0].modified = GS_MEMBER_MODIFIED;
+
+ // Set default positions
+ g->position[0].mode=0x11;
+ strcpy(g->position[0].name,"GuildMaster");
+ strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie");
+ for(i=1;i<MAX_GUILDPOSITION-1;i++)
+ sprintf(g->position[i].name,"Position %d",i+1);
+
+ // Initialize guild property
+ g->max_member=16;
+ g->average_lv=master->lv;
+ for(i=0;i<MAX_GUILDSKILL;i++)
+ g->skill[i].id=i + GD_SKILLBASE;
+ g->guild_id= -1; //Request to create guild.
+
+ // Create the guild
+ if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) {
+ //Failed to Create guild....
+ ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master);
+ mapif_guild_created(fd,account_id,NULL);
+ aFree(g);
+ return 0;
+ }
+ ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master);
+
+ //Add to cache
+ idb_put(guild_db_, g->guild_id, g);
+
+ // Report to client
+ mapif_guild_created(fd,account_id,g);
+ mapif_guild_info(fd,g);
+
+ if(log_inter)
+ inter_log("guild %s (id=%d) created by master %s (id=%d)" RETCODE,
+ name, g->guild_id, master->name, master->account_id );
+
+ return 0;
+}
+
+// Return guild info to client
+int mapif_parse_GuildInfo(int fd,int guild_id)
+{
+ struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex]
+ if(g)
+ {
+ if (!guild_calcinfo(g))
+ mapif_guild_info(fd,g);
+ }
+ else
+ mapif_guild_noinfo(fd,guild_id); // Failed to load info
+ return 0;
+}
+
+// Add member to guild
+int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m)
+{
+ struct guild * g;
+ int i;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL){
+ // Failed to add
+ mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1);
+ return 0;
+ }
+
+ // Find an empty slot
+ for(i=0;i<g->max_member;i++)
+ {
+ if(g->member[i].account_id==0)
+ {
+ memcpy(&g->member[i],m,sizeof(struct guild_member));
+ g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED);
+ mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0);
+ if (!guild_calcinfo(g)) //Send members if it was not invoked.
+ mapif_guild_info(fd,g);
+
+ g->save_flag |= GS_MEMBER;
+ if (g->save_flag&GS_REMOVE)
+ g->save_flag&=~GS_REMOVE;
+ return 0;
+ }
+ }
+
+ // Failed to add
+ mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1);
+ return 0;
+}
+
+// Delete member from guild
+int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes)
+{
+ struct guild * g = inter_guild_fromsql(guild_id);
+
+ if(g){
+ int i;
+ // Find the member
+ for(i=0;i<g->max_member;i++){
+ if( g->member[i].account_id==account_id && g->member[i].char_id==char_id)
+ {
+ if(flag)
+ {
+ // Write expulsion reason
+ int j;
+ // Find an empty slot
+ for(j=0;j<MAX_GUILDEXPULSION;j++){
+ if(g->expulsion[j].account_id==0)
+ break;
+ }
+ // Expulsion list is full, flush the oldest one
+ if(j==MAX_GUILDEXPULSION){
+ for(j=0;j<MAX_GUILDEXPULSION-1;j++)
+ g->expulsion[j]=g->expulsion[j+1];
+ j=MAX_GUILDEXPULSION-1;
+ }
+ // Save the expulsion
+ g->expulsion[j].account_id=account_id;
+ memcpy(g->expulsion[j].acc,"dummy",NAME_LENGTH-1);
+ memcpy(g->expulsion[j].name,g->member[i].name,NAME_LENGTH-1);
+ memcpy(g->expulsion[j].mes,mes,40);
+ }
+
+ mapif_guild_leaved(guild_id,account_id,char_id,flag,g->member[i].name,mes);
+ inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id);
+
+ memset(&g->member[i],0,sizeof(struct guild_member));
+
+ if(!guild_check_empty(g)) {
+ break;
+ }
+ //Guild empty? break it.
+ mapif_parse_BreakGuild(-1,guild_id); //Break the guild.
+ return 0;
+ }
+ }
+ //Update member info.
+ if (!guild_calcinfo(g))
+ mapif_guild_info(fd,g);
+ g->save_flag |= GS_EXPULSION;
+ }else{
+ // Unknown guild, just update the player
+ sprintf(tmp_sql, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'",char_db, account_id,char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ /* mapif_guild_leaved(guild_id,account_id,char_id,flag,g->member[i].name,mes); */
+ }
+
+ return 0;
+}
+
+// Change member info
+int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,
+ int account_id,int char_id,int online,int lv,int class_)
+{
+ // Could speed up by manipulating only guild_member
+ struct guild * g;
+ int i,alv,c;
+ int prev_count;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ prev_count = g->connect_member;
+ g->connect_member=0;
+
+ for(i=0,alv=0,c=0;i<g->max_member;i++)
+ {
+ // Found the member
+ if(g->member[i].account_id==account_id && g->member[i].char_id==char_id)
+ {
+ g->member[i].online=online;
+ g->member[i].lv=lv;
+ g->member[i].class_=class_;
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfoshort(g,i);
+ }
+ if( g->member[i].account_id>0 )
+ {
+ if (g->member[i].lv > 0)
+ {
+ alv+=g->member[i].lv;
+ c++;
+ }
+ else
+ {
+ ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv);
+ }
+ }
+ if( g->member[i].online )
+ g->connect_member++;
+ }
+
+ if (c)
+ {
+ alv = alv/c;
+ if (g->connect_member != prev_count || g->average_lv != alv)
+ {
+ g->average_lv=alv;
+ g->save_flag |= GS_CONNECT;
+ }
+ if (g->save_flag & GS_REMOVE)
+ g->save_flag &= ~GS_REMOVE;
+ }
+ g->save_flag |= GS_MEMBER; //Update guild member data
+ return 0;
+}
+
+// BreakGuild
+int mapif_parse_BreakGuild(int fd,int guild_id)
+{
+ struct guild * g;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ // Delete guild from sql
+ //printf("- Delete guild %d from guild\n",guild_id);
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ //printf("- Update guild %d of char\n",guild_id);
+ sprintf(tmp_sql, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'",char_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ mapif_guild_broken(guild_id,0);
+
+ if(log_inter)
+ inter_log("guild %s (id=%d) broken" RETCODE,g->name,guild_id);
+
+ //Remove the guild from memory. [Skotlex]
+ idb_remove(guild_db_, guild_id);
+ return 0;
+}
+
+// Forward Guild message to others map servers
+int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len)
+{
+ return mapif_guild_message(guild_id,account_id,mes,len, fd);
+}
+
+// Modification of the guild
+int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len)
+{
+ struct guild * g;
+ short dw=*((short *)data);
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ switch(type)
+ {
+ case GBI_GUILDLV:
+ ShowDebug("GBI_GUILDLV\n");
+ if(dw>0 && g->guild_lv+dw<=50)
+ {
+ g->guild_lv+=dw;
+ g->skill_point+=dw;
+ }
+ else if(dw<0 && g->guild_lv+dw>=1)
+ g->guild_lv+=dw;
+ mapif_guild_info(-1,g);
+ g->save_flag |= GS_LEVEL;
+ return 0;
+ default:
+ ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type);
+ break;
+ }
+ mapif_guild_basicinfochanged(guild_id,type,data,len);
+ return 0;
+}
+
+// Modification of the guild
+int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,
+ int type,const char *data,int len)
+{
+ // Could make some improvement in speed, because only change guild_member
+ int i;
+ struct guild * g;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ // Search the member
+ for(i=0;i<g->max_member;i++)
+ if( g->member[i].account_id==account_id &&
+ g->member[i].char_id==char_id )
+ break;
+
+ // Not Found
+ if(i==g->max_member){
+ ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n",
+ account_id,char_id,guild_id,g->name);
+ return 0;
+ }
+
+ switch(type)
+ {
+ case GMI_POSITION:
+ {
+ g->member[i].position=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER;
+ break;
+ }
+ case GMI_EXP:
+ { // EXP
+ unsigned int exp, old_exp=g->member[i].exp;
+ g->member[i].exp=*((unsigned int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ if (g->member[i].exp > old_exp)
+ {
+ exp = g->member[i].exp - old_exp;
+
+ // Compute gained exp
+ if (guild_exp_rate != 100)
+ exp = exp*guild_exp_rate/100;
+
+ // Update guild exp
+ if (exp > UINT_MAX - g->exp)
+ g->exp = UINT_MAX;
+ else
+ g->exp+=exp;
+
+ guild_calcinfo(g);
+ mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,4);
+ g->save_flag |= GS_LEVEL;
+ }
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER;
+ break;
+ }
+ case GMI_HAIR:
+ {
+ g->member[i].hair=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER; //Save new data.
+ break;
+ }
+ case GMI_HAIR_COLOR:
+ {
+ g->member[i].hair_color=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER; //Save new data.
+ break;
+ }
+ case GMI_GENDER:
+ {
+ g->member[i].gender=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER; //Save new data.
+ break;
+ }
+ case GMI_CLASS:
+ {
+ g->member[i].class_=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER; //Save new data.
+ break;
+ }
+ case GMI_LEVEL:
+ {
+ g->member[i].lv=*((int *)data);
+ g->member[i].modified = GS_MEMBER_MODIFIED;
+ mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len);
+ g->save_flag |= GS_MEMBER; //Save new data.
+ break;
+ }
+ default:
+ ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type);
+ break;
+ }
+ return 0;
+}
+
+int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender)
+{
+ return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender));
+}
+
+// Change a position desc
+int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p)
+{
+ // Could make some improvement in speed, because only change guild_position
+ struct guild * g;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION)
+ return 0;
+
+ memcpy(&g->position[idx],p,sizeof(struct guild_position));
+ mapif_guild_position(g,idx);
+ ShowInfo("int_guild: position data changed (Guild %d, position %d)\n",guild_id, idx);
+ g->position[idx].modified = GS_POSITION_MODIFIED;
+ g->save_flag |= GS_POSITION; // Change guild_position
+ return 0;
+}
+
+// Guild Skill UP
+int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id)
+{
+ struct guild * g;
+ int idx = skill_num - GD_SKILLBASE;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL)
+ return 0;
+
+ if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lv<10 )
+ {
+ g->skill[idx].lv++;
+ g->skill_point--;
+ if (!guild_calcinfo(g))
+ mapif_guild_info(-1,g);
+ mapif_guild_skillupack(guild_id,skill_num,account_id);
+ g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill
+ }
+ return 0;
+}
+
+//Manual deletion of an alliance when partnering guild does not exists. [Skotlex]
+static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag)
+{
+ int i;
+ char name[NAME_LENGTH];
+ for(i=0;i<MAX_GUILDALLIANCE;i++)
+ if(g->alliance[i].guild_id == guild_id)
+ {
+ strcpy(name, g->alliance[i].name);
+ g->alliance[i].guild_id=0;
+ break;
+ }
+ if (i == MAX_GUILDALLIANCE)
+ return -1;
+
+ mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name);
+ g->save_flag |= GS_ALLIANCE;
+ return 0;
+}
+
+// Alliance modification
+int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,
+ int account_id1,int account_id2,int flag)
+{
+ // Could speed up
+ struct guild *g[2];
+ int j,i;
+ g[0] = inter_guild_fromsql(guild_id1);
+ g[1] = inter_guild_fromsql(guild_id2);
+
+ if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild.
+ return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild.
+
+ if(g[0]==NULL || g[1]==NULL)
+ return 0;
+
+ if(flag&GUILD_ALLIANCE_REMOVE)
+ {
+ // Remove alliance/opposition, in case of alliance, remove on both side
+ for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++)
+ {
+ for(j=0;j<MAX_GUILDALLIANCE;j++)
+ {
+ if(g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK))
+ {
+ g[i]->alliance[j].guild_id=0;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Add alliance, in case of alliance, add on both side
+ for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++)
+ {
+ // Search an empty slot
+ for(j=0;j<MAX_GUILDALLIANCE;j++)
+ {
+ if(g[i]->alliance[j].guild_id==0)
+ {
+ g[i]->alliance[j].guild_id=g[1-i]->guild_id;
+ memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH-1);
+ // Set alliance type
+ g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK;
+ break;
+ }
+ }
+ }
+ }
+
+ // Send on all map the new alliance/opposition
+ mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name);
+
+ // Mark the two guild to be saved
+ g[0]->save_flag |= GS_ALLIANCE;
+ g[1]->save_flag |= GS_ALLIANCE;
+ return 0;
+}
+
+// Change guild message
+int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2)
+{
+ struct guild *g;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ memcpy(g->mes1,mes1,60);
+ memcpy(g->mes2,mes2,120);
+ g->save_flag |= GS_MES; //Change mes of guild
+ return mapif_guild_notice(g);
+}
+
+int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data)
+{
+ struct guild * g;
+
+ g = inter_guild_fromsql(guild_id);
+ if(g==NULL)
+ return 0;
+
+ if (len > sizeof(g->emblem_data))
+ len = sizeof(g->emblem_data);
+
+ memcpy(g->emblem_data,data,len);
+ g->emblem_len=len;
+ g->emblem_id++;
+ g->save_flag |= GS_EMBLEM; //Change guild
+ return mapif_guild_emblem(g);
+}
+
+int mapif_parse_GuildCastleDataLoad(int fd,int castle_id,int index) // <Agit>
+{
+ struct guild_castle gc;
+ if (!inter_guildcastle_fromsql(castle_id, &gc)) {
+ return mapif_guild_castle_dataload(castle_id,0,0);
+ }
+ switch(index){
+ case 1: return mapif_guild_castle_dataload(gc.castle_id,index,gc.guild_id); break;
+ case 2: return mapif_guild_castle_dataload(gc.castle_id,index,gc.economy); break;
+ case 3: return mapif_guild_castle_dataload(gc.castle_id,index,gc.defense); break;
+ case 4: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerE); break;
+ case 5: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerD); break;
+ case 6: return mapif_guild_castle_dataload(gc.castle_id,index,gc.nextTime); break;
+ case 7: return mapif_guild_castle_dataload(gc.castle_id,index,gc.payTime); break;
+ case 8: return mapif_guild_castle_dataload(gc.castle_id,index,gc.createTime); break;
+ case 9: return mapif_guild_castle_dataload(gc.castle_id,index,gc.visibleC); break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-10].visible); break;
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-18].hp); break;
+ default:
+ ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index);
+ return 0;
+ }
+}
+
+int mapif_parse_GuildCastleDataSave(int fd,int castle_id,int index,int value) // <Agit>
+{
+ struct guild_castle gc;
+ if(!inter_guildcastle_fromsql(castle_id, &gc))
+ return mapif_guild_castle_datasave(castle_id,index,value);
+
+ switch(index){
+ case 1:
+ if( gc.guild_id!=value ){
+ int gid=(value)?value:gc.guild_id;
+ struct guild *g=idb_get(guild_db_, gid);
+ if(log_inter)
+ inter_log("guild %s (id=%d) %s castle id=%d" RETCODE,
+ (g)?g->name:"??" ,gid, (value)?"occupy":"abandon", castle_id);
+ }
+ gc.guild_id = value;
+ if(gc.guild_id == 0) {
+ //Delete guardians.
+ memset(&gc.guardian, 0, sizeof(gc.guardian));
+ }
+ break;
+ case 2: gc.economy = value; break;
+ case 3: gc.defense = value; break;
+ case 4: gc.triggerE = value; break;
+ case 5: gc.triggerD = value; break;
+ case 6: gc.nextTime = value; break;
+ case 7: gc.payTime = value; break;
+ case 8: gc.createTime = value; break;
+ case 9: gc.visibleC = value; break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ gc.guardian[index-10].visible = value; break;
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ gc.guardian[index-18].hp = value; break; // end additions [Valaris]
+ default:
+ ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index);
+ return 0;
+ }
+ inter_guildcastle_tosql(&gc);
+ mapif_guild_castle_datasave(gc.castle_id,index,value);
+ return 0;
+}
+
+int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len)
+{
+ struct guild * g;
+ struct guild_member gm;
+ int pos;
+
+ g = inter_guild_fromsql(guild_id);
+
+ if(g==NULL || len > NAME_LENGTH)
+ return 0;
+
+ // Find member (name)
+ for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++);
+
+ if (pos == g->max_member)
+ return 0; //Character not found??
+
+ // Switch current and old GM
+ memcpy(&gm, &g->member[pos], sizeof (struct guild_member));
+ memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member));
+ memcpy(&g->member[0], &gm, sizeof(struct guild_member));
+
+ // Switch positions
+ g->member[pos].position = g->member[0].position;
+ g->member[pos].modified = GS_MEMBER_MODIFIED;
+ g->member[0].position = 0; //Position 0: guild Master.
+ g->member[0].modified = GS_MEMBER_MODIFIED;
+
+ strncpy(g->master, name, len);
+ if (len < NAME_LENGTH)
+ g->master[len] = '\0';
+
+ ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name);
+ g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data.
+ return mapif_guild_master_changed(g, pos);
+}
+
+// ƒMƒ‹ƒhƒ`ƒFƒbƒN—v‹
+int mapif_parse_GuildCheck(int fd,int guild_id,int account_id,int char_id)
+{
+ // What does this mean? Check if belong to another guild?
+ return 0;
+}
+
+// map server ‚©‚η‚̒ʐM
+// E‚PƒpƒPƒbƒg‚Μ‚έ‰πΝ‚·‚ι‚±‚Ζ
+// EƒpƒPƒbƒg’·ƒf[ƒ^‚Νinter.c‚ΙƒZƒbƒg‚΅‚Δ‚¨‚­‚±‚Ζ
+// EƒpƒPƒbƒg’·ƒ`ƒFƒbƒN‚βARFIFOSKIP‚ΝŒΔ‚Ρo‚΅Œ³‚ōs‚ν‚κ‚ι‚̂ōs‚Α‚Δ‚Ν‚Θ‚η‚Θ‚’
+// EƒGƒ‰[‚Θ‚η0(false)A‚»‚€‚Ε‚Θ‚’‚Θ‚η1(true)‚π‚©‚¦‚³‚Θ‚―‚κ‚Ξ‚Θ‚η‚Θ‚’
+int inter_guild_parse_frommap(int fd)
+{
+ RFIFOHEAD(fd);
+ switch(RFIFOW(fd,0)){
+ case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break;
+ case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break;
+ case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break;
+ case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break;
+ case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break;
+ case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break;
+ case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break;
+ case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break;
+ case 0x3038: mapif_parse_GuildCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
+ case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break;
+ case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break;
+ case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break;
+ case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); break;
+ case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break;
+ case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break;
+ case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break;
+ case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),RFIFOB(fd,4)); break;
+ case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int inter_guild_mapif_init(int fd)
+{
+ return mapif_guild_castle_alldataload(fd);
+}
+
+// ƒT[ƒo[‚©‚η’E‘ή—v‹iƒLƒƒƒ‰νœ—pj
+int inter_guild_leave(int guild_id,int account_id,int char_id)
+{
+ return mapif_parse_GuildLeave(-1,guild_id,account_id,char_id,0,"** Character Deleted **");
+}
+
+int inter_guild_broken(int guild_id)
+{
+ return mapif_guild_broken(guild_id, 0);
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/int_guild.h b/src/char_sql/int_guild.h
index 88836a2a1..4b153574b 100644
--- a/src/char_sql/int_guild.h
+++ b/src/char_sql/int_guild.h
@@ -1,35 +1,35 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _INT_GUILD_SQL_H_
-#define _INT_GUILD_SQL_H_
-
-int inter_guild_parse_frommap(int fd);
-int inter_guild_sql_init(void);
-void inter_guild_sql_final(void);
-int inter_guild_mapif_init(int fd);
-int inter_guild_leave(int guild_id,int account_id,int char_id);
-int mapif_parse_BreakGuild(int fd,int guild_id);
-int inter_guild_broken(int guild_id);
-int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender);
-int inter_guild_CharOnline(int char_id, int guild_id);
-int inter_guild_CharOffline(int char_id, int guild_id);
-
-#define GS_BASIC 0x0001
-#define GS_MEMBER 0x0002
-#define GS_POSITION 0x0004
-#define GS_ALLIANCE 0x0008
-#define GS_EXPULSION 0x0010
-#define GS_SKILL 0x0020
-#define GS_EMBLEM 0x0040
-#define GS_CONNECT 0x0080
-#define GS_LEVEL 0x0100
-#define GS_MES 0x0200
-#define GS_MASK 0x03FF
-#define GS_BASIC_MASK (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES)
-#define GS_REMOVE 0x8000
-
-//For the TXT->SQL converter.
-int inter_guild_tosql(struct guild *g,int flag);
-int inter_guildcastle_tosql(struct guild_castle *gc);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_GUILD_SQL_H_
+#define _INT_GUILD_SQL_H_
+
+int inter_guild_parse_frommap(int fd);
+int inter_guild_sql_init(void);
+void inter_guild_sql_final(void);
+int inter_guild_mapif_init(int fd);
+int inter_guild_leave(int guild_id,int account_id,int char_id);
+int mapif_parse_BreakGuild(int fd,int guild_id);
+int inter_guild_broken(int guild_id);
+int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender);
+int inter_guild_CharOnline(int char_id, int guild_id);
+int inter_guild_CharOffline(int char_id, int guild_id);
+
+#define GS_BASIC 0x0001
+#define GS_MEMBER 0x0002
+#define GS_POSITION 0x0004
+#define GS_ALLIANCE 0x0008
+#define GS_EXPULSION 0x0010
+#define GS_SKILL 0x0020
+#define GS_EMBLEM 0x0040
+#define GS_CONNECT 0x0080
+#define GS_LEVEL 0x0100
+#define GS_MES 0x0200
+#define GS_MASK 0x03FF
+#define GS_BASIC_MASK (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES)
+#define GS_REMOVE 0x8000
+
+//For the TXT->SQL converter.
+int inter_guild_tosql(struct guild *g,int flag);
+int inter_guildcastle_tosql(struct guild_castle *gc);
+#endif
diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c
index d39114602..e726b15d3 100644
--- a/src/char_sql/int_homun.c
+++ b/src/char_sql/int_homun.c
@@ -1,296 +1,296 @@
-// Homunculus saving by Albator and Orn for eAthena.
-// GNU/GPL rulez !
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "char.h"
-#include "../common/strlib.h"
-#include "../common/showmsg.h"
-
-struct s_homunculus *homun_pt;
-
-#ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
-#else
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-#endif
-
-
-int inter_homunculus_sql_init(void){
- //memory alloc
- homun_pt = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1);
- return 0;
-}
-void inter_homunculus_sql_final(void){
- if (homun_pt) aFree(homun_pt);
- return;
-}
-
-int mapif_saved_homunculus(int fd, int account_id, unsigned char flag)
-{
- WFIFOHEAD(fd, 7);
- WFIFOW(fd,0) = 0x3892;
- WFIFOL(fd,2) = account_id;
- WFIFOB(fd,6) = flag;
- WFIFOSET(fd, 7);
- return 0;
-}
-int mapif_info_homunculus(int fd, int account_id, struct s_homunculus *hd)
-{
- WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
- WFIFOW(fd,0) = 0x3891;
- WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
- WFIFOL(fd,4) = account_id;
- WFIFOB(fd,8) = 1; // account loaded with success
-
- memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus));
- WFIFOSET(fd, sizeof(struct s_homunculus)+9);
- return 0;
-}
-
-int mapif_homunculus_deleted(int fd, int flag)
-{
- WFIFOHEAD(fd, 3);
- WFIFOW(fd, 0) = 0x3893;
- WFIFOB(fd,2) = flag; //Flag 1 = success
- WFIFOSET(fd, 3);
- return 0;
-
-}
-int mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag)
-{
- WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
- WFIFOW(fd,0) = 0x3890;
- WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
- WFIFOL(fd,4) = account_id;
- WFIFOB(fd,8)= flag;
- memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus));
- WFIFOSET(fd, WFIFOW(fd,2));
- return 0;
-}
-
-// Save/Update Homunculus Skills
-int mapif_save_homunculus_skills(struct s_homunculus *hd)
-{
- int i;
-
- for(i=0; i<MAX_HOMUNSKILL; i++)
- {
- if(hd->hskill[i].id != 0 && hd->hskill[i].lv != 0 )
- {
- sprintf(tmp_sql,"REPLACE INTO `skill_homunculus` (`homun_id`, `id`, `lv`) VALUES (%d, %d, %d)",
- hd->hom_id, hd->hskill[i].id, hd->hskill[i].lv);
-
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- }
- }
-
- return 1;
-}
-
-int mapif_save_homunculus(int fd, int account_id, struct s_homunculus *hd)
-{
- int flag =1;
- char t_name[NAME_LENGTH*2];
- jstrescapecpy(t_name, hd->name);
-
- if(hd->hom_id==0) // new homunculus
- {
- ShowInfo("New homunculus name : %s\n",hd->name);
-
- sprintf(tmp_sql, "INSERT INTO `homunculus` "
- "(`char_id`, `class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) "
- "VALUES ('%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
- hd->char_id, hd->class_,t_name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
- hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize);
-
- }
- else
- {
- sprintf(tmp_sql, "UPDATE `homunculus` SET `char_id`='%d', `class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'",
- hd->char_id, hd->class_,t_name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
- hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id);
- }
-
- if(mysql_query(&mysql_handle, tmp_sql)){
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- flag = 0;
- }
-
- if(hd->hom_id==0 && flag!=0)
- hd->hom_id = (int)mysql_insert_id(&mysql_handle); // new homunculus
- else
- {
- flag = mapif_save_homunculus_skills(hd);
- mapif_saved_homunculus(fd, account_id, flag);
- }
- return flag;
-}
-
-
-
-// Load an homunculus
-int mapif_load_homunculus(int fd){
- int i;
- RFIFOHEAD(fd);
- memset(homun_pt, 0, sizeof(struct s_homunculus));
-
- sprintf(tmp_sql,"SELECT `homun_id`,`char_id`,`class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `homunculus` WHERE `homun_id`='%lu'", RFIFOL(fd,6));
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
-
- return 0;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
- sql_row = mysql_fetch_row(sql_res);
-
- homun_pt->hom_id = RFIFOL(fd,6) ; //RFIFOL(fd,2);
- homun_pt->class_ = atoi(sql_row[2]);
- memcpy(homun_pt->name, sql_row[3],NAME_LENGTH-1);
- homun_pt->char_id = atoi(sql_row[1]);
- homun_pt->level = atoi(sql_row[4]);
- homun_pt->exp = atoi(sql_row[5]);
- homun_pt->intimacy = atoi(sql_row[6]);
- homun_pt->hunger = atoi(sql_row[7]);
- homun_pt->str = atoi(sql_row[8]);
- homun_pt->agi = atoi(sql_row[9]);
- homun_pt->vit = atoi(sql_row[10]);
- homun_pt->int_ = atoi(sql_row[11]);
- homun_pt->dex = atoi(sql_row[12]);
- homun_pt->luk = atoi(sql_row[13]);
- homun_pt->hp = atoi(sql_row[14]);
- homun_pt->max_hp = atoi(sql_row[15]);
- homun_pt->sp = atoi(sql_row[16]);
- homun_pt->max_sp = atoi(sql_row[17]);
- homun_pt->skillpts = atoi(sql_row[18]);
- homun_pt->rename_flag = atoi(sql_row[19]);
- homun_pt->vaporize = atoi(sql_row[20]);
- }
- if(homun_pt->hunger < 0)
- homun_pt->hunger = 0;
- else if(homun_pt->hunger > 100)
- homun_pt->hunger = 100;
- if(homun_pt->intimacy < 0)
- homun_pt->intimacy = 0;
- else if(homun_pt->intimacy > 100000)
- homun_pt->intimacy = 100000;
-
- mysql_free_result(sql_res);
-
- // Load Homunculus Skill
- memset(homun_pt->hskill, 0, sizeof(homun_pt->hskill));
-
- sprintf(tmp_sql,"SELECT `id`,`lv` FROM `skill_homunculus` WHERE `homun_id`=%d",homun_pt->hom_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- sql_res = mysql_store_result(&mysql_handle);
- if(sql_res){
- while((sql_row = mysql_fetch_row(sql_res))){
- i = (atoi(sql_row[0])-HM_SKILLBASE-1);
- homun_pt->hskill[i].id = atoi(sql_row[0]);
- homun_pt->hskill[i].lv = atoi(sql_row[1]);
- }
- }
-
- mysql_free_result(sql_res);
-
- ShowInfo("Homunculus loaded (%d - %s).\n", homun_pt->hom_id, homun_pt->name);
- return mapif_info_homunculus(fd, RFIFOL(fd,2), homun_pt);
-}
-
-
-
-int mapif_delete_homunculus(int fd)
-{
- RFIFOHEAD(fd);
- sprintf(tmp_sql, "DELETE FROM `homunculus` WHERE `homun_id` = '%lu'", RFIFOL(fd,2));
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return mapif_homunculus_deleted(fd, 0);
- }
-
- sprintf(tmp_sql, "DELETE FROM `skill_homunculus` WHERE `homun_id` = '%lu'", RFIFOL(fd,2));
- if(mysql_query(&mysql_handle, tmp_sql))
- {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return mapif_homunculus_deleted(fd, 0);
- }
- return mapif_homunculus_deleted(fd, 1);
-}
-
-int mapif_rename_homun_ack(int fd, int account_id, int char_id, unsigned char flag, char *name){
- WFIFOHEAD(fd, NAME_LENGTH+12);
- WFIFOW(fd, 0) =0x3894;
- WFIFOL(fd, 2) =account_id;
- WFIFOL(fd, 6) =char_id;
- WFIFOB(fd, 10) =flag;
- memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
- WFIFOSET(fd, NAME_LENGTH+12);
-
- return 0;
-}
-
-int mapif_rename_homun(int fd, int account_id, int char_id, char *name){
- int i;
-
- // Check Authorised letters/symbols in the name of the homun
- if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
- for (i = 0; i < NAME_LENGTH && name[i]; i++)
- if (strchr(char_name_letters, name[i]) == NULL) {
- mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
- return 0;
- }
- } else if (char_name_option == 2) { // 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) {
- mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
- return 0;
- }
- }
-
- mapif_rename_homun_ack(fd, account_id, char_id, 1, name);
- return 0;
-}
-
-int mapif_parse_CreateHomunculus(int fd)
-{
- RFIFOHEAD(fd);
- memcpy(homun_pt, RFIFOP(fd,8), sizeof(struct s_homunculus));
- // Save in sql db
- if(mapif_save_homunculus(fd,RFIFOL(fd,4), homun_pt))
- return mapif_homunculus_created(fd, RFIFOL(fd,4), homun_pt, 1); // send homun_id
- return mapif_homunculus_created(fd, RFIFOL(fd,4), homun_pt, 0); // fail
-}
-
-int inter_homunculus_parse_frommap(int fd){
- RFIFOHEAD(fd);
- switch(RFIFOW(fd, 0)){
- case 0x3090: mapif_parse_CreateHomunculus(fd); break;
- case 0x3091: mapif_load_homunculus(fd); break;
- case 0x3092: mapif_save_homunculus(fd, RFIFOW(fd,4), (struct s_homunculus*) RFIFOP(fd, 8)); break;
- case 0x3093: mapif_delete_homunculus(fd); break; // doesn't need to be parse, very simple packet...
- case 0x3094: mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10)); break;
- default:
- return 0;
- }
- return 1;
-}
+// Homunculus saving by Albator and Orn for eAthena.
+// GNU/GPL rulez !
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "char.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+
+struct s_homunculus *homun_pt;
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+
+int inter_homunculus_sql_init(void){
+ //memory alloc
+ homun_pt = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1);
+ return 0;
+}
+void inter_homunculus_sql_final(void){
+ if (homun_pt) aFree(homun_pt);
+ return;
+}
+
+int mapif_saved_homunculus(int fd, int account_id, unsigned char flag)
+{
+ WFIFOHEAD(fd, 7);
+ WFIFOW(fd,0) = 0x3892;
+ WFIFOL(fd,2) = account_id;
+ WFIFOB(fd,6) = flag;
+ WFIFOSET(fd, 7);
+ return 0;
+}
+int mapif_info_homunculus(int fd, int account_id, struct s_homunculus *hd)
+{
+ WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
+ WFIFOW(fd,0) = 0x3891;
+ WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
+ WFIFOL(fd,4) = account_id;
+ WFIFOB(fd,8) = 1; // account loaded with success
+
+ memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus));
+ WFIFOSET(fd, sizeof(struct s_homunculus)+9);
+ return 0;
+}
+
+int mapif_homunculus_deleted(int fd, int flag)
+{
+ WFIFOHEAD(fd, 3);
+ WFIFOW(fd, 0) = 0x3893;
+ WFIFOB(fd,2) = flag; //Flag 1 = success
+ WFIFOSET(fd, 3);
+ return 0;
+
+}
+int mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag)
+{
+ WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
+ WFIFOW(fd,0) = 0x3890;
+ WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
+ WFIFOL(fd,4) = account_id;
+ WFIFOB(fd,8)= flag;
+ memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus));
+ WFIFOSET(fd, WFIFOW(fd,2));
+ return 0;
+}
+
+// Save/Update Homunculus Skills
+int mapif_save_homunculus_skills(struct s_homunculus *hd)
+{
+ int i;
+
+ for(i=0; i<MAX_HOMUNSKILL; i++)
+ {
+ if(hd->hskill[i].id != 0 && hd->hskill[i].lv != 0 )
+ {
+ sprintf(tmp_sql,"REPLACE INTO `skill_homunculus` (`homun_id`, `id`, `lv`) VALUES (%d, %d, %d)",
+ hd->hom_id, hd->hskill[i].id, hd->hskill[i].lv);
+
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int mapif_save_homunculus(int fd, int account_id, struct s_homunculus *hd)
+{
+ int flag =1;
+ char t_name[NAME_LENGTH*2];
+ jstrescapecpy(t_name, hd->name);
+
+ if(hd->hom_id==0) // new homunculus
+ {
+ ShowInfo("New homunculus name : %s\n",hd->name);
+
+ sprintf(tmp_sql, "INSERT INTO `homunculus` "
+ "(`char_id`, `class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) "
+ "VALUES ('%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ hd->char_id, hd->class_,t_name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
+ hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize);
+
+ }
+ else
+ {
+ sprintf(tmp_sql, "UPDATE `homunculus` SET `char_id`='%d', `class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'",
+ hd->char_id, hd->class_,t_name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
+ hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id);
+ }
+
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ flag = 0;
+ }
+
+ if(hd->hom_id==0 && flag!=0)
+ hd->hom_id = (int)mysql_insert_id(&mysql_handle); // new homunculus
+ else
+ {
+ flag = mapif_save_homunculus_skills(hd);
+ mapif_saved_homunculus(fd, account_id, flag);
+ }
+ return flag;
+}
+
+
+
+// Load an homunculus
+int mapif_load_homunculus(int fd){
+ int i;
+ RFIFOHEAD(fd);
+ memset(homun_pt, 0, sizeof(struct s_homunculus));
+
+ sprintf(tmp_sql,"SELECT `homun_id`,`char_id`,`class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `homunculus` WHERE `homun_id`='%lu'", RFIFOL(fd,6));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+
+ return 0;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+
+ homun_pt->hom_id = RFIFOL(fd,6) ; //RFIFOL(fd,2);
+ homun_pt->class_ = atoi(sql_row[2]);
+ memcpy(homun_pt->name, sql_row[3],NAME_LENGTH-1);
+ homun_pt->char_id = atoi(sql_row[1]);
+ homun_pt->level = atoi(sql_row[4]);
+ homun_pt->exp = atoi(sql_row[5]);
+ homun_pt->intimacy = atoi(sql_row[6]);
+ homun_pt->hunger = atoi(sql_row[7]);
+ homun_pt->str = atoi(sql_row[8]);
+ homun_pt->agi = atoi(sql_row[9]);
+ homun_pt->vit = atoi(sql_row[10]);
+ homun_pt->int_ = atoi(sql_row[11]);
+ homun_pt->dex = atoi(sql_row[12]);
+ homun_pt->luk = atoi(sql_row[13]);
+ homun_pt->hp = atoi(sql_row[14]);
+ homun_pt->max_hp = atoi(sql_row[15]);
+ homun_pt->sp = atoi(sql_row[16]);
+ homun_pt->max_sp = atoi(sql_row[17]);
+ homun_pt->skillpts = atoi(sql_row[18]);
+ homun_pt->rename_flag = atoi(sql_row[19]);
+ homun_pt->vaporize = atoi(sql_row[20]);
+ }
+ if(homun_pt->hunger < 0)
+ homun_pt->hunger = 0;
+ else if(homun_pt->hunger > 100)
+ homun_pt->hunger = 100;
+ if(homun_pt->intimacy < 0)
+ homun_pt->intimacy = 0;
+ else if(homun_pt->intimacy > 100000)
+ homun_pt->intimacy = 100000;
+
+ mysql_free_result(sql_res);
+
+ // Load Homunculus Skill
+ memset(homun_pt->hskill, 0, sizeof(homun_pt->hskill));
+
+ sprintf(tmp_sql,"SELECT `id`,`lv` FROM `skill_homunculus` WHERE `homun_id`=%d",homun_pt->hom_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if(sql_res){
+ while((sql_row = mysql_fetch_row(sql_res))){
+ i = (atoi(sql_row[0])-HM_SKILLBASE-1);
+ homun_pt->hskill[i].id = atoi(sql_row[0]);
+ homun_pt->hskill[i].lv = atoi(sql_row[1]);
+ }
+ }
+
+ mysql_free_result(sql_res);
+
+ ShowInfo("Homunculus loaded (%d - %s).\n", homun_pt->hom_id, homun_pt->name);
+ return mapif_info_homunculus(fd, RFIFOL(fd,2), homun_pt);
+}
+
+
+
+int mapif_delete_homunculus(int fd)
+{
+ RFIFOHEAD(fd);
+ sprintf(tmp_sql, "DELETE FROM `homunculus` WHERE `homun_id` = '%lu'", RFIFOL(fd,2));
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return mapif_homunculus_deleted(fd, 0);
+ }
+
+ sprintf(tmp_sql, "DELETE FROM `skill_homunculus` WHERE `homun_id` = '%lu'", RFIFOL(fd,2));
+ if(mysql_query(&mysql_handle, tmp_sql))
+ {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return mapif_homunculus_deleted(fd, 0);
+ }
+ return mapif_homunculus_deleted(fd, 1);
+}
+
+int mapif_rename_homun_ack(int fd, int account_id, int char_id, unsigned char flag, char *name){
+ WFIFOHEAD(fd, NAME_LENGTH+12);
+ WFIFOW(fd, 0) =0x3894;
+ WFIFOL(fd, 2) =account_id;
+ WFIFOL(fd, 6) =char_id;
+ WFIFOB(fd, 10) =flag;
+ memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
+ WFIFOSET(fd, NAME_LENGTH+12);
+
+ return 0;
+}
+
+int mapif_rename_homun(int fd, int account_id, int char_id, char *name){
+ int i;
+
+ // Check Authorised letters/symbols in the name of the homun
+ if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+ for (i = 0; i < NAME_LENGTH && name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL) {
+ mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+ return 0;
+ }
+ } else if (char_name_option == 2) { // 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) {
+ mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+ return 0;
+ }
+ }
+
+ mapif_rename_homun_ack(fd, account_id, char_id, 1, name);
+ return 0;
+}
+
+int mapif_parse_CreateHomunculus(int fd)
+{
+ RFIFOHEAD(fd);
+ memcpy(homun_pt, RFIFOP(fd,8), sizeof(struct s_homunculus));
+ // Save in sql db
+ if(mapif_save_homunculus(fd,RFIFOL(fd,4), homun_pt))
+ return mapif_homunculus_created(fd, RFIFOL(fd,4), homun_pt, 1); // send homun_id
+ return mapif_homunculus_created(fd, RFIFOL(fd,4), homun_pt, 0); // fail
+}
+
+int inter_homunculus_parse_frommap(int fd){
+ RFIFOHEAD(fd);
+ switch(RFIFOW(fd, 0)){
+ case 0x3090: mapif_parse_CreateHomunculus(fd); break;
+ case 0x3091: mapif_load_homunculus(fd); break;
+ case 0x3092: mapif_save_homunculus(fd, RFIFOW(fd,4), (struct s_homunculus*) RFIFOP(fd, 8)); break;
+ case 0x3093: mapif_delete_homunculus(fd); break; // doesn't need to be parse, very simple packet...
+ case 0x3094: mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10)); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/char_sql/int_homun.h b/src/char_sql/int_homun.h
index e274c9ee1..cfc46ca24 100644
--- a/src/char_sql/int_homun.h
+++ b/src/char_sql/int_homun.h
@@ -1,14 +1,14 @@
-// Homunculus saving by Albator and Orn for eAthena.
-// GNU/GPL rulez !
-
-#ifndef _INT_HOMUN_H_
-#define _INT_HOMUN_H_
-
-int inter_homunculus_sql_init(void);
-void inter_homunculus_sql_final(void);
-int mapif_save_homunculus(struct s_homunculus *hd);
-int mapif_load_homunculus(int fd);
-int mapif_delete_homunculus(int fd);
-int inter_homunculus_parse_frommap(int fd);
-
-#endif
+// Homunculus saving by Albator and Orn for eAthena.
+// GNU/GPL rulez !
+
+#ifndef _INT_HOMUN_H_
+#define _INT_HOMUN_H_
+
+int inter_homunculus_sql_init(void);
+void inter_homunculus_sql_final(void);
+int mapif_save_homunculus(struct s_homunculus *hd);
+int mapif_load_homunculus(int fd);
+int mapif_delete_homunculus(int fd);
+int inter_homunculus_parse_frommap(int fd);
+
+#endif
diff --git a/src/char_sql/int_party.c b/src/char_sql/int_party.c
index da5506903..e39c826d4 100644
--- a/src/char_sql/int_party.c
+++ b/src/char_sql/int_party.c
@@ -1,937 +1,937 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by hack
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include "char.h"
-#include "../common/db.h"
-#include "../common/strlib.h"
-#include "../common/socket.h"
-#include "../common/showmsg.h"
-
-#ifndef TXT_SQL_CONVERT
-struct party_data {
- struct party party;
- unsigned int min_lv, max_lv;
- int family; //Is this party a family? if so, this holds the child id.
- unsigned char size; //Total size of party.
-};
-
-static struct party_data *party_pt;
-static struct dbt *party_db_;
-
-int mapif_party_broken(int party_id,int flag);
-int party_check_empty(struct party_data *p);
-int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id);
-int party_check_exp_share(struct party_data *p);
-int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag);
-
-#ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
-#else
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-#endif
-
-//Updates party's level range and unsets even share if broken.
-static int int_party_check_lv(struct party_data *p) {
- int i;
- unsigned int lv;
- p->min_lv = UINT_MAX;
- p->max_lv = 0;
- for(i=0;i<MAX_PARTY;i++){
- if(!p->party.member[i].online)
- continue;
-
- lv=p->party.member[i].lv;
- if (lv < p->min_lv) p->min_lv = lv;
- if (lv > p->max_lv) p->max_lv = lv;
- }
-
- if (p->party.exp && !party_check_exp_share(p)) {
- p->party.exp = 0;
- mapif_party_optionchanged(0, &p->party, 0, 0);
- return 0;
- }
- return 1;
-}
-//Calculates the state of a party.
-static void int_party_calc_state(struct party_data *p)
-{
- int i;
- unsigned int lv;
- p->min_lv = UINT_MAX;
- p->max_lv = 0;
- p->party.count =
- p->size =
- p->family = 0;
-
- //Check party size
- for(i=0;i<MAX_PARTY;i++){
- if (!p->party.member[i].lv) continue;
- p->size++;
- if(p->party.member[i].online)
- p->party.count++;
- }
- if(p->size == 3) {
- //Check Family State.
- p->family = char_family(
- p->party.member[0].char_id,
- p->party.member[1].char_id,
- p->party.member[2].char_id
- );
- }
- //max/min levels.
- for(i=0;i<MAX_PARTY;i++){
- lv=p->party.member[i].lv;
- if (!lv) continue;
- if(p->party.member[i].online &&
- //On families, the kid is not counted towards exp share rules.
- p->party.member[i].char_id != p->family)
- {
- if( lv < p->min_lv ) p->min_lv=lv;
- if( p->max_lv < lv ) p->max_lv=lv;
- }
- }
-
- if (p->party.exp && !party_check_exp_share(p)) {
- p->party.exp = 0; //Set off even share.
- mapif_party_optionchanged(0, &p->party, 0, 0);
- }
- return;
-}
-#endif //TXT_SQL_CONVERT
-// Save party to mysql
-int inter_party_tosql(struct party *p, int flag, int index)
-{
- // 'party' ('party_id','name','exp','item','leader_id','leader_char')
- char t_name[NAME_LENGTH*2]; //Required for jstrescapecpy [Skotlex]
- int party_id;
- if (p == NULL || p->party_id == 0)
- return 0;
- party_id = p->party_id;
-
-#ifdef NOISY
- ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name);
-#endif
- jstrescapecpy(t_name, p->name);
-
-#ifndef TXT_SQL_CONVERT
- if (flag&PS_BREAK) { //Break the party
- // we'll skip name-checking and just reset everyone with the same party id [celest]
- sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- //Remove from memory
- idb_remove(party_db_, party_id);
- return 1;
- }
-#endif //TXT_SQL_CONVERT
- if(flag&PS_CREATE) { //Create party
-#ifndef TXT_SQL_CONVERT
- sprintf(tmp_sql, "INSERT INTO `%s` "
- "(`name`, `exp`, `item`, `leader_id`, `leader_char`) "
- "VALUES ('%s', '%d', '%d', '%d', '%d')",
- party_db, t_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- if(mysql_field_count(&mysql_handle) == 0 &&
- mysql_insert_id(&mysql_handle) != 0)
- party_id = p->party_id = (int)mysql_insert_id(&mysql_handle);
- else //Failed to retrieve ID??
- return 0;
-#else
- //During conversion, you want to specify the id, and allow overwriting
- //(in case someone is re-running the process.
- sprintf(tmp_sql, "REPLACE INTO `%s` "
- "(`party_id`, `name`, `exp`, `item`, `leader_id`, `leader_char`) "
- "VALUES ('%d', '%s', '%d', '%d', '%d', '%d')",
- party_db, p->party_id, t_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
-#endif
- }
-
-#ifndef TXT_SQL_CONVERT
- if (flag&PS_BASIC) {
- //Update party info.
- sprintf(tmp_sql, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'",
- party_db, t_name, p->exp, p->item, party_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- if (flag&PS_LEADER) {
- //Update leader
- sprintf(tmp_sql, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'",
- party_db, p->member[index].account_id, p->member[index].char_id, party_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- if (flag&PS_ADDMEMBER) {
- //Add one party member.
- sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'",
- char_db, party_id, p->member[index].account_id, p->member[index].char_id);
- if (mysql_query (&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- if (flag&PS_DELMEMBER) {
- //Remove one party member.
- sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'",
- char_db, party_id, p->member[index].account_id, p->member[index].char_id);
- if (mysql_query (&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-#endif //TXT_SQL_CONVERT
- if (save_log)
- ShowInfo("Party Saved (%d - %s)\n", party_id, p->name);
- return 1;
-}
-#ifndef TXT_SQL_CONVERT
-// Read party from mysql
-struct party_data *inter_party_fromsql(int party_id)
-{
- int leader_id = 0, leader_char = 0;
- struct party_data *p;
-#ifdef NOISY
- ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id);
-#endif
- if (party_id <=0)
- return NULL;
-
- //Load from memory
- if ((p = idb_get(party_db_, party_id)) != NULL)
- return p;
-
- p = party_pt;
- memset(p, 0, sizeof(struct party_data));
-
- sprintf(tmp_sql, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'",
- party_db, party_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return NULL;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if (!sql_res)
- return NULL;
- sql_row = mysql_fetch_row(sql_res);
- if (!sql_row) {
- mysql_free_result(sql_res);
- return NULL;
- }
- p->party.party_id = party_id;
- memcpy(&p->party.name, sql_row[1], NAME_LENGTH-1);
- p->party.exp = atoi(sql_row[2])?1:0;
- p->party.item = atoi(sql_row[3]);
- leader_id = atoi(sql_row[4]);
- leader_char = atoi(sql_row[5]);
- mysql_free_result(sql_res);
-
- // Load members
- sprintf(tmp_sql,"SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'",
- char_db, party_id); // TBR
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return NULL;
- }
- sql_res = mysql_store_result(&mysql_handle);
- if (sql_res) {
- int i;
- for (i = 0; i<MAX_PARTY && (sql_row = mysql_fetch_row(sql_res)); i++) {
- struct party_member *m = &p->party.member[i];
- m->account_id = atoi(sql_row[0]);
- m->char_id = atoi(sql_row[1]);
- m->leader = (m->account_id == leader_id && m->char_id == leader_char)?1:0;
- memcpy(m->name, sql_row[2], NAME_LENGTH);
- m->lv = atoi(sql_row[3]);
- m->map = mapindex_name2id(sql_row[4]);
- m->online = atoi(sql_row[5])?1:0;
- m->class_ = atoi(sql_row[6]);
- }
- mysql_free_result(sql_res);
- }
-
- if (save_log)
- ShowInfo("Party loaded (%d - %s).\n",party_id, p->party.name);
- //Add party to memory.
- p = aCalloc(1, sizeof(struct party_data));
- memcpy(p, party_pt, sizeof(struct party_data));
- //init state
- int_party_calc_state(p);
- idb_put(party_db_, party_id, p);
- return p;
-}
-
-int inter_party_sql_init(void){
- //memory alloc
- party_db_ = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
- party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1);
- if (!party_pt) {
- ShowFatalError("inter_party_sql_init: Out of Memory!\n");
- exit(1);
- }
-
- /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex]
- ShowStatus("cleaning party table...\n");
- sprintf (tmp_sql,
- "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL",
- party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- */
- return 0;
-}
-
-void inter_party_sql_final(void)
-{
- party_db_->destroy(party_db_, NULL);
- aFree(party_pt);
- return;
-}
-
-// Search for the party according to its name
-struct party_data* search_partyname(char *str)
-{
- char t_name[NAME_LENGTH*2];
- int party_id;
-
- sprintf(tmp_sql,"SELECT `party_id` FROM `%s` WHERE `name`='%s'",party_db, jstrescapecpy(t_name,str));
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res==NULL || mysql_num_rows(sql_res)<=0)
- {
- if (sql_res) mysql_free_result(sql_res);
- return NULL;
- }
- sql_row = mysql_fetch_row(sql_res);
- party_id = sql_row?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
-
- return inter_party_fromsql(party_id);
-}
-
-// Returns whether this party can keep having exp share or not.
-int party_check_exp_share(struct party_data *p)
-{
- return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level);
-}
-
-// Is there any member in the party?
-int party_check_empty(struct party_data *p)
-{
- int i;
- if (p==NULL||p->party.party_id==0) return 1;
- for(i=0;i<MAX_PARTY && !p->party.member[i].account_id;i++);
- if (i < MAX_PARTY) return 0;
- // If there is no member, then break the party
- mapif_party_broken(p->party.party_id,0);
- inter_party_tosql(&p->party, PS_BREAK, 0);
- return 1;
-}
-
-
-// Check if a member is in two party, not necessary :)
-int party_check_conflict(int party_id,int account_id,int char_id)
-{
- return 0;
-}
-
-//-------------------------------------------------------------------
-// map server‚ւ̒ʐM
-
-// ƒp[ƒeƒBμ¬‰Β”Ϋ
-int mapif_party_created(int fd,int account_id,int char_id,struct party *p)
-{
- WFIFOHEAD(fd, 39);
- WFIFOW(fd,0)=0x3820;
- WFIFOL(fd,2)=account_id;
- WFIFOL(fd,6)=char_id;
- if(p!=NULL){
- WFIFOB(fd,10)=0;
- WFIFOL(fd,11)=p->party_id;
- memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH);
- ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name);
- }else{
- WFIFOB(fd,10)=1;
- WFIFOL(fd,11)=0;
- memset(WFIFOP(fd,15),0,NAME_LENGTH);
- }
- WFIFOSET(fd,39);
-
- return 0;
-}
-
-// ƒp[ƒeƒBξ•ρŒ©‚Β‚©‚η‚Έ
-int mapif_party_noinfo(int fd,int party_id)
-{
- WFIFOHEAD(fd,8);
- WFIFOW(fd,0)=0x3821;
- WFIFOW(fd,2)=8;
- WFIFOL(fd,4)=party_id;
- WFIFOSET(fd,8);
- ShowWarning("int_party: info not found %d\n",party_id);
- return 0;
-}
-// ƒp[ƒeƒBξ•ρ‚ά‚Ζ‚ί‘—‚θ
-int mapif_party_info(int fd,struct party *p)
-{
- unsigned char buf[5+sizeof(struct party)];
- WBUFW(buf,0)=0x3821;
- WBUFW(buf,2)=4+sizeof(struct party);
- memcpy(buf+4,p,sizeof(struct party));
-
- if(fd<0)
- mapif_sendall(buf,WBUFW(buf,2));
- else
- mapif_send(fd,buf,WBUFW(buf,2));
- return 0;
-}
-// ƒp[ƒeƒBƒƒ“ƒo’Η‰Α‰Β”Ϋ
-int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) {
- WFIFOHEAD(fd, 15);
- WFIFOW(fd,0) = 0x3822;
- WFIFOL(fd,2) = party_id;
- WFIFOL(fd,6) = account_id;
- WFIFOL(fd,10) = char_id;
- WFIFOB(fd,14) = flag;
- WFIFOSET(fd,15);
-
- return 0;
-}
-
-// ƒp[ƒeƒBέ’θ•ΟX’Κ’m
-int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag)
-{
- unsigned char buf[16];
- WBUFW(buf,0)=0x3823;
- WBUFL(buf,2)=p->party_id;
- WBUFL(buf,6)=account_id;
- WBUFW(buf,10)=p->exp;
- WBUFW(buf,12)=p->item;
- WBUFB(buf,14)=flag;
- if(flag==0)
- mapif_sendall(buf,15);
- else
- mapif_send(fd,buf,15);
- return 0;
-}
-
-//Checks whether the even-share setting of a party is broken when a character logs in. [Skotlex]
-int inter_party_logged(int party_id, int account_id, int char_id)
-{
- struct party_data *p;
- int i;
-
- if (party_id <= 0)
- return 0;
-
- if (!party_id)
- return 0;
- p = inter_party_fromsql(party_id);
- if(!p) //Non existant party?
- return 0;
-
- for(i = 0; i < MAX_PARTY; i++)
- if(p->party.member[i].account_id==account_id &&
- p->party.member[i].char_id==char_id)
- {
- if (!p->party.member[i].online) {
- p->party.member[i].online = 1;
- p->party.count++;
- if(p->party.member[i].lv < p->min_lv ||
- p->party.member[i].lv > p->max_lv)
- int_party_check_lv(p);
- }
- break;
- }
-
- return 0;
-}
-
-// ƒp[ƒeƒB’E‘ή’Κ’m
-int mapif_party_leaved(int party_id,int account_id, int char_id) {
- unsigned char buf[16];
-
- WBUFW(buf,0) = 0x3824;
- WBUFL(buf,2) = party_id;
- WBUFL(buf,6) = account_id;
- WBUFL(buf,10) = char_id;
- mapif_sendall(buf, 14);
- return 0;
-}
-
-// ƒp[ƒeƒBƒ}ƒbƒvXV’Κ’m
-int mapif_party_membermoved(struct party *p,int idx)
-{
- unsigned char buf[20];
-
- WBUFW(buf,0) = 0x3825;
- WBUFL(buf,2) = p->party_id;
- WBUFL(buf,6) = p->member[idx].account_id;
- WBUFL(buf,10) = p->member[idx].char_id;
- WBUFW(buf,14) = p->member[idx].map;
- WBUFB(buf,16) = p->member[idx].online;
- WBUFW(buf,17) = p->member[idx].lv;
- mapif_sendall(buf, 19);
- return 0;
-}
-
-// ƒp[ƒeƒB‰πŽU’Κ’m
-int mapif_party_broken(int party_id,int flag)
-{
- unsigned char buf[16];
- WBUFW(buf,0)=0x3826;
- WBUFL(buf,2)=party_id;
- WBUFB(buf,6)=flag;
- mapif_sendall(buf,7);
- //printf("int_party: broken %d\n",party_id);
- return 0;
-}
-// ƒp[ƒeƒB“ΰ”­ŒΎ
-int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd)
-{
- unsigned char buf[512];
- WBUFW(buf,0)=0x3827;
- WBUFW(buf,2)=len+12;
- WBUFL(buf,4)=party_id;
- WBUFL(buf,8)=account_id;
- memcpy(WBUFP(buf,12),mes,len);
- mapif_sendallwos(sfd, buf,len+12);
- return 0;
-}
-
-//-------------------------------------------------------------------
-// map server‚©‚η‚̒ʐM
-
-
-// Create Party
-int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader)
-{
- struct party_data *p;
- int i;
- if( (p=search_partyname(name))!=NULL){
- mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
- return 0;
- }
- // Check Authorised letters/symbols in the name of the character
- if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
- for (i = 0; i < NAME_LENGTH && name[i]; i++)
- if (strchr(char_name_letters, name[i]) == NULL) {
- mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
- return 0;
- }
- } else if (char_name_option == 2) { // 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) {
- mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
- return 0;
- }
- }
-
- p= aCalloc(1, sizeof(struct party_data));
-
- memcpy(p->party.name,name,NAME_LENGTH);
- p->party.exp=0;
- p->party.item=(item?1:0)|(item2?2:0);
-
- memcpy(&p->party.member[0], leader, sizeof(struct party_member));
- p->party.member[0].leader=1;
- p->party.member[0].online=1;
-
- p->party.party_id=-1;//New party.
- if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) {
- //Add party to db
- int_party_calc_state(p);
- idb_put(party_db_, p->party.party_id, p);
- mapif_party_created(fd,leader->account_id,leader->char_id,&p->party);
- mapif_party_info(fd,&p->party);
- } else { //Failed to create party.
- aFree(p);
- mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
- }
-
- return 0;
-}
-// ƒp[ƒeƒBξ•ρ—v‹
-int mapif_parse_PartyInfo(int fd,int party_id)
-{
- struct party_data *p;
- p = inter_party_fromsql(party_id);
-
- if (p)
- mapif_party_info(fd,&p->party);
- else
- mapif_party_noinfo(fd,party_id);
- return 0;
-}
-// ƒp[ƒeƒB’Η‰Α—v‹
-int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) {
- struct party_data *p;
- int i;
-
- p = inter_party_fromsql(party_id);
-
- if(!p || p->size == MAX_PARTY){
- mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,1);
- return 0;
- }
-
- for(i=0;i<MAX_PARTY;i++){
- if(p->party.member[i].account_id)
- continue;
-
- memcpy(&p->party.member[i], member, sizeof(struct party_member));
- p->party.member[i].leader=0;
- if (p->party.member[i].online) p->party.count++;
- p->size++;
- if (p->size == 3) //Check family state.
- int_party_calc_state(p);
- else //Check even share range.
- if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) {
- if (p->family) p->family = 0; //Family state broken.
- int_party_check_lv(p);
- }
-
- mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,0);
- mapif_party_info(-1,&p->party);
- inter_party_tosql(&p->party, PS_ADDMEMBER, i);
- return 0;
- }
- //Party full
- mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,1);
- return 0;
-}
-// ƒp[ƒeƒB[έ’θ•ΟX—v‹
-int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item)
-{
- struct party_data *p;
- int flag = 0;
- p = inter_party_fromsql(party_id);
-
- if(!p)
- return 0;
-
- p->party.exp=exp;
- if( exp && !party_check_exp_share(p) ){
- flag|=0x01;
- p->party.exp=0;
- }
- p->party.item = item&0x3; //Filter out invalid values.
- mapif_party_optionchanged(fd,&p->party,account_id,flag);
- inter_party_tosql(&p->party, PS_BASIC, 0);
- return 0;
-}
-// ƒp[ƒeƒB’E‘ή—v‹
-int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
-{
- struct party_data *p;
- int i,j=-1;
-
- p = inter_party_fromsql(party_id);
- if (!p) { //Party does not exists?
- sprintf(tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return 0;
- }
-
- for (i = 0; i < MAX_PARTY; i++) {
- if(p->party.member[i].account_id == account_id &&
- p->party.member[i].char_id == char_id) {
- break;
- }
- }
- if (i >= MAX_PARTY)
- return 0; //Member not found?
-
- mapif_party_leaved(party_id, account_id, char_id);
-
- if (p->party.member[i].leader){
- p->party.member[i].account_id = 0;
- for (j = 0; j < MAX_PARTY; j++) {
- if (!p->party.member[j].account_id)
- continue;
- mapif_party_leaved(party_id, p->party.member[j].account_id, p->party.member[j].char_id);
- p->party.member[j].account_id = 0;
- }
- //Party gets deleted on the check_empty call below.
- } else {
- inter_party_tosql(&p->party,PS_DELMEMBER,i);
- j = p->party.member[i].lv;
- if(p->party.member[i].online) p->party.count--;
- memset(&p->party.member[i], 0, sizeof(struct party_member));
- p->size--;
- if (j == p->min_lv || j == p->max_lv || p->family)
- {
- if(p->family) p->family = 0; //Family state broken.
- int_party_check_lv(p);
- }
- }
-
- if (party_check_empty(p) == 0)
- mapif_party_info(-1,&p->party);
- return 0;
-}
-// When member goes to other map
-int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv)
-{
- struct party_data *p;
- int i;
-
- p = inter_party_fromsql(party_id);
- if (p == NULL)
- return 0;
-
- for(i = 0; i < MAX_PARTY; i++) {
- if(p->party.member[i].account_id == account_id &&
- p->party.member[i].char_id == char_id)
- {
- p->party.member[i].map = map;
- if (p->party.member[i].online != online)
- {
- p->party.member[i].online = online;
- if (online)
- p->party.count++;
- else
- p->party.count--;
- // Even share check situations: Family state (always breaks)
- // character logging on/off is max/min level (update level range)
- // or character logging on/off has a different level (update level range using new level)
- if (p->family ||
- (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) ||
- (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv))
- )
- {
- p->party.member[i].lv = lv;
- int_party_check_lv(p);
- }
- }
- if (p->party.member[i].lv != lv) {
- if(p->party.member[i].lv == p->min_lv ||
- p->party.member[i].lv == p->max_lv)
- {
- p->party.member[i].lv = lv;
- int_party_check_lv(p);
- } else
- p->party.member[i].lv = lv;
- }
- mapif_party_membermoved(&p->party, i);
- break;
- }
- }
- return 0;
-}
-// ƒp[ƒeƒB‰πŽU—v‹
-int mapif_parse_BreakParty(int fd,int party_id)
-{
- struct party_data *p;
-
- p = inter_party_fromsql(party_id);
-
- if(!p)
- return 0;
- inter_party_tosql(&p->party,PS_BREAK,0);
- mapif_party_broken(fd,party_id);
- return 0;
-}
-// ƒp[ƒeƒBƒƒbƒZ[ƒW‘—M
-int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len)
-{
- return mapif_party_message(party_id,account_id,mes,len, fd);
-}
-// ƒp[ƒeƒBƒ`ƒFƒbƒN—v‹
-int mapif_parse_PartyCheck(int fd,int party_id,int account_id,int char_id)
-{
- return party_check_conflict(party_id,account_id,char_id);
-}
-
-int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id)
-{
- struct party_data *p;
- int i;
-
- p = inter_party_fromsql(party_id);
-
- if(!p)
- return 0;
-
- for (i = 0; i < MAX_PARTY; i++)
- {
- if(p->party.member[i].leader)
- p->party.member[i].leader = 0;
- if(p->party.member[i].account_id == account_id &&
- p->party.member[i].char_id == char_id)
- {
- p->party.member[i].leader = 1;
- inter_party_tosql(&p->party,PS_LEADER, i);
- }
- }
- return 1;
-}
-
-// map server ‚©‚η‚̒ʐM
-// E‚PƒpƒPƒbƒg‚Μ‚έ‰πΝ‚·‚ι‚±‚Ζ
-// EƒpƒPƒbƒg’·ƒf[ƒ^‚Νinter.c‚ΙƒZƒbƒg‚΅‚Δ‚¨‚­‚±‚Ζ
-// EƒpƒPƒbƒg’·ƒ`ƒFƒbƒN‚βARFIFOSKIP‚ΝŒΔ‚Ρo‚΅Œ³‚ōs‚ν‚κ‚ι‚̂ōs‚Α‚Δ‚Ν‚Θ‚η‚Θ‚’
-// EƒGƒ‰[‚Θ‚η0(false)A‚»‚€‚Ε‚Θ‚’‚Θ‚η1(true)‚π‚©‚¦‚³‚Θ‚―‚κ‚Ξ‚Θ‚η‚Θ‚’
-int inter_party_parse_frommap(int fd)
-{
- RFIFOHEAD(fd);
- switch(RFIFOW(fd,0)) {
- case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break;
- case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break;
- case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break;
- case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break;
- case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
- case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break;
- case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break;
- case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break;
- case 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
- case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
- default:
- return 0;
- }
- return 1;
-}
-
-// ƒT[ƒo[‚©‚η’E‘ή—v‹iƒLƒƒƒ‰νœ—pj
-int inter_party_leave(int party_id,int account_id, int char_id)
-{
- return mapif_parse_PartyLeave(-1,party_id,account_id, char_id);
-}
-
-int inter_party_CharOnline(int char_id, int party_id) {
- struct party_data *p;
- int i;
-
- if (party_id == -1) {
- //Get party_id from the database
- sprintf (tmp_sql , "SELECT party_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if(sql_res == NULL)
- return 0; //Eh? No party?
-
- sql_row = mysql_fetch_row(sql_res);
- party_id = sql_row?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
- }
- if (party_id == 0)
- return 0; //No party...
-
- p = inter_party_fromsql(party_id);
- if(!p) {
- ShowError("Character %d's party %d not found!\n", char_id, party_id);
- return 0;
- }
-
- //Set member online
- for(i=0; i<MAX_PARTY; i++) {
- if (p->party.member[i].char_id == char_id) {
- if (!p->party.member[i].online) {
- p->party.member[i].online = 1;
- p->party.count++;
- if (p->party.member[i].lv < p->min_lv ||
- p->party.member[i].lv > p->max_lv)
- int_party_check_lv(p);
- }
- break;
- }
- }
- return 1;
-}
-
-int inter_party_CharOffline(int char_id, int party_id) {
- struct party_data *p=NULL;
- int i;
-
- if (party_id == -1) {
- //Get guild_id from the database
- sprintf (tmp_sql , "SELECT party_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
-
- sql_res = mysql_store_result(&mysql_handle) ;
- if(sql_res == NULL)
- return 0; //Eh? No party?
-
- sql_row = mysql_fetch_row(sql_res);
- party_id = sql_row?atoi(sql_row[0]):0;
- mysql_free_result(sql_res);
- }
- if (party_id == 0)
- return 0; //No party...
-
- //Character has a party, set character offline and check if they were the only member online
- if ((p = inter_party_fromsql(party_id)) == NULL)
- return 0;
-
- //Set member offline
- for(i=0; i< MAX_PARTY; i++) {
- if(p->party.member[i].char_id == char_id)
- {
- p->party.member[i].online = 0;
- p->party.count--;
- if(p->party.member[i].lv == p->min_lv ||
- p->party.member[i].lv == p->max_lv)
- int_party_check_lv(p);
- break;
- }
- }
-
- if(!p->party.count)
- //Parties don't have any data that needs be saved at this point... so just remove it from memory.
- idb_remove(party_db_, party_id);
- return 1;
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by hack
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "char.h"
+#include "../common/db.h"
+#include "../common/strlib.h"
+#include "../common/socket.h"
+#include "../common/showmsg.h"
+
+#ifndef TXT_SQL_CONVERT
+struct party_data {
+ struct party party;
+ unsigned int min_lv, max_lv;
+ int family; //Is this party a family? if so, this holds the child id.
+ unsigned char size; //Total size of party.
+};
+
+static struct party_data *party_pt;
+static struct dbt *party_db_;
+
+int mapif_party_broken(int party_id,int flag);
+int party_check_empty(struct party_data *p);
+int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id);
+int party_check_exp_share(struct party_data *p);
+int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag);
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+//Updates party's level range and unsets even share if broken.
+static int int_party_check_lv(struct party_data *p) {
+ int i;
+ unsigned int lv;
+ p->min_lv = UINT_MAX;
+ p->max_lv = 0;
+ for(i=0;i<MAX_PARTY;i++){
+ if(!p->party.member[i].online)
+ continue;
+
+ lv=p->party.member[i].lv;
+ if (lv < p->min_lv) p->min_lv = lv;
+ if (lv > p->max_lv) p->max_lv = lv;
+ }
+
+ if (p->party.exp && !party_check_exp_share(p)) {
+ p->party.exp = 0;
+ mapif_party_optionchanged(0, &p->party, 0, 0);
+ return 0;
+ }
+ return 1;
+}
+//Calculates the state of a party.
+static void int_party_calc_state(struct party_data *p)
+{
+ int i;
+ unsigned int lv;
+ p->min_lv = UINT_MAX;
+ p->max_lv = 0;
+ p->party.count =
+ p->size =
+ p->family = 0;
+
+ //Check party size
+ for(i=0;i<MAX_PARTY;i++){
+ if (!p->party.member[i].lv) continue;
+ p->size++;
+ if(p->party.member[i].online)
+ p->party.count++;
+ }
+ if(p->size == 3) {
+ //Check Family State.
+ p->family = char_family(
+ p->party.member[0].char_id,
+ p->party.member[1].char_id,
+ p->party.member[2].char_id
+ );
+ }
+ //max/min levels.
+ for(i=0;i<MAX_PARTY;i++){
+ lv=p->party.member[i].lv;
+ if (!lv) continue;
+ if(p->party.member[i].online &&
+ //On families, the kid is not counted towards exp share rules.
+ p->party.member[i].char_id != p->family)
+ {
+ if( lv < p->min_lv ) p->min_lv=lv;
+ if( p->max_lv < lv ) p->max_lv=lv;
+ }
+ }
+
+ if (p->party.exp && !party_check_exp_share(p)) {
+ p->party.exp = 0; //Set off even share.
+ mapif_party_optionchanged(0, &p->party, 0, 0);
+ }
+ return;
+}
+#endif //TXT_SQL_CONVERT
+// Save party to mysql
+int inter_party_tosql(struct party *p, int flag, int index)
+{
+ // 'party' ('party_id','name','exp','item','leader_id','leader_char')
+ char t_name[NAME_LENGTH*2]; //Required for jstrescapecpy [Skotlex]
+ int party_id;
+ if (p == NULL || p->party_id == 0)
+ return 0;
+ party_id = p->party_id;
+
+#ifdef NOISY
+ ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name);
+#endif
+ jstrescapecpy(t_name, p->name);
+
+#ifndef TXT_SQL_CONVERT
+ if (flag&PS_BREAK) { //Break the party
+ // we'll skip name-checking and just reset everyone with the same party id [celest]
+ sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ //Remove from memory
+ idb_remove(party_db_, party_id);
+ return 1;
+ }
+#endif //TXT_SQL_CONVERT
+ if(flag&PS_CREATE) { //Create party
+#ifndef TXT_SQL_CONVERT
+ sprintf(tmp_sql, "INSERT INTO `%s` "
+ "(`name`, `exp`, `item`, `leader_id`, `leader_char`) "
+ "VALUES ('%s', '%d', '%d', '%d', '%d')",
+ party_db, t_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ if(mysql_field_count(&mysql_handle) == 0 &&
+ mysql_insert_id(&mysql_handle) != 0)
+ party_id = p->party_id = (int)mysql_insert_id(&mysql_handle);
+ else //Failed to retrieve ID??
+ return 0;
+#else
+ //During conversion, you want to specify the id, and allow overwriting
+ //(in case someone is re-running the process.
+ sprintf(tmp_sql, "REPLACE INTO `%s` "
+ "(`party_id`, `name`, `exp`, `item`, `leader_id`, `leader_char`) "
+ "VALUES ('%d', '%s', '%d', '%d', '%d', '%d')",
+ party_db, p->party_id, t_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+#endif
+ }
+
+#ifndef TXT_SQL_CONVERT
+ if (flag&PS_BASIC) {
+ //Update party info.
+ sprintf(tmp_sql, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'",
+ party_db, t_name, p->exp, p->item, party_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ if (flag&PS_LEADER) {
+ //Update leader
+ sprintf(tmp_sql, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'",
+ party_db, p->member[index].account_id, p->member[index].char_id, party_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ if (flag&PS_ADDMEMBER) {
+ //Add one party member.
+ sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'",
+ char_db, party_id, p->member[index].account_id, p->member[index].char_id);
+ if (mysql_query (&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ if (flag&PS_DELMEMBER) {
+ //Remove one party member.
+ sprintf (tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'",
+ char_db, party_id, p->member[index].account_id, p->member[index].char_id);
+ if (mysql_query (&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+#endif //TXT_SQL_CONVERT
+ if (save_log)
+ ShowInfo("Party Saved (%d - %s)\n", party_id, p->name);
+ return 1;
+}
+#ifndef TXT_SQL_CONVERT
+// Read party from mysql
+struct party_data *inter_party_fromsql(int party_id)
+{
+ int leader_id = 0, leader_char = 0;
+ struct party_data *p;
+#ifdef NOISY
+ ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id);
+#endif
+ if (party_id <=0)
+ return NULL;
+
+ //Load from memory
+ if ((p = idb_get(party_db_, party_id)) != NULL)
+ return p;
+
+ p = party_pt;
+ memset(p, 0, sizeof(struct party_data));
+
+ sprintf(tmp_sql, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'",
+ party_db, party_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return NULL;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (!sql_res)
+ return NULL;
+ sql_row = mysql_fetch_row(sql_res);
+ if (!sql_row) {
+ mysql_free_result(sql_res);
+ return NULL;
+ }
+ p->party.party_id = party_id;
+ memcpy(&p->party.name, sql_row[1], NAME_LENGTH-1);
+ p->party.exp = atoi(sql_row[2])?1:0;
+ p->party.item = atoi(sql_row[3]);
+ leader_id = atoi(sql_row[4]);
+ leader_char = atoi(sql_row[5]);
+ mysql_free_result(sql_res);
+
+ // Load members
+ sprintf(tmp_sql,"SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'",
+ char_db, party_id); // TBR
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return NULL;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if (sql_res) {
+ int i;
+ for (i = 0; i<MAX_PARTY && (sql_row = mysql_fetch_row(sql_res)); i++) {
+ struct party_member *m = &p->party.member[i];
+ m->account_id = atoi(sql_row[0]);
+ m->char_id = atoi(sql_row[1]);
+ m->leader = (m->account_id == leader_id && m->char_id == leader_char)?1:0;
+ memcpy(m->name, sql_row[2], NAME_LENGTH);
+ m->lv = atoi(sql_row[3]);
+ m->map = mapindex_name2id(sql_row[4]);
+ m->online = atoi(sql_row[5])?1:0;
+ m->class_ = atoi(sql_row[6]);
+ }
+ mysql_free_result(sql_res);
+ }
+
+ if (save_log)
+ ShowInfo("Party loaded (%d - %s).\n",party_id, p->party.name);
+ //Add party to memory.
+ p = aCalloc(1, sizeof(struct party_data));
+ memcpy(p, party_pt, sizeof(struct party_data));
+ //init state
+ int_party_calc_state(p);
+ idb_put(party_db_, party_id, p);
+ return p;
+}
+
+int inter_party_sql_init(void){
+ //memory alloc
+ party_db_ = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+ party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1);
+ if (!party_pt) {
+ ShowFatalError("inter_party_sql_init: Out of Memory!\n");
+ exit(1);
+ }
+
+ /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex]
+ ShowStatus("cleaning party table...\n");
+ sprintf (tmp_sql,
+ "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL",
+ party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ */
+ return 0;
+}
+
+void inter_party_sql_final(void)
+{
+ party_db_->destroy(party_db_, NULL);
+ aFree(party_pt);
+ return;
+}
+
+// Search for the party according to its name
+struct party_data* search_partyname(char *str)
+{
+ char t_name[NAME_LENGTH*2];
+ int party_id;
+
+ sprintf(tmp_sql,"SELECT `party_id` FROM `%s` WHERE `name`='%s'",party_db, jstrescapecpy(t_name,str));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res==NULL || mysql_num_rows(sql_res)<=0)
+ {
+ if (sql_res) mysql_free_result(sql_res);
+ return NULL;
+ }
+ sql_row = mysql_fetch_row(sql_res);
+ party_id = sql_row?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+
+ return inter_party_fromsql(party_id);
+}
+
+// Returns whether this party can keep having exp share or not.
+int party_check_exp_share(struct party_data *p)
+{
+ return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level);
+}
+
+// Is there any member in the party?
+int party_check_empty(struct party_data *p)
+{
+ int i;
+ if (p==NULL||p->party.party_id==0) return 1;
+ for(i=0;i<MAX_PARTY && !p->party.member[i].account_id;i++);
+ if (i < MAX_PARTY) return 0;
+ // If there is no member, then break the party
+ mapif_party_broken(p->party.party_id,0);
+ inter_party_tosql(&p->party, PS_BREAK, 0);
+ return 1;
+}
+
+
+// Check if a member is in two party, not necessary :)
+int party_check_conflict(int party_id,int account_id,int char_id)
+{
+ return 0;
+}
+
+//-------------------------------------------------------------------
+// map server‚ւ̒ʐM
+
+// ƒp[ƒeƒBμ¬‰Β”Ϋ
+int mapif_party_created(int fd,int account_id,int char_id,struct party *p)
+{
+ WFIFOHEAD(fd, 39);
+ WFIFOW(fd,0)=0x3820;
+ WFIFOL(fd,2)=account_id;
+ WFIFOL(fd,6)=char_id;
+ if(p!=NULL){
+ WFIFOB(fd,10)=0;
+ WFIFOL(fd,11)=p->party_id;
+ memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH);
+ ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name);
+ }else{
+ WFIFOB(fd,10)=1;
+ WFIFOL(fd,11)=0;
+ memset(WFIFOP(fd,15),0,NAME_LENGTH);
+ }
+ WFIFOSET(fd,39);
+
+ return 0;
+}
+
+// ƒp[ƒeƒBξ•ρŒ©‚Β‚©‚η‚Έ
+int mapif_party_noinfo(int fd,int party_id)
+{
+ WFIFOHEAD(fd,8);
+ WFIFOW(fd,0)=0x3821;
+ WFIFOW(fd,2)=8;
+ WFIFOL(fd,4)=party_id;
+ WFIFOSET(fd,8);
+ ShowWarning("int_party: info not found %d\n",party_id);
+ return 0;
+}
+// ƒp[ƒeƒBξ•ρ‚ά‚Ζ‚ί‘—‚θ
+int mapif_party_info(int fd,struct party *p)
+{
+ unsigned char buf[5+sizeof(struct party)];
+ WBUFW(buf,0)=0x3821;
+ WBUFW(buf,2)=4+sizeof(struct party);
+ memcpy(buf+4,p,sizeof(struct party));
+
+ if(fd<0)
+ mapif_sendall(buf,WBUFW(buf,2));
+ else
+ mapif_send(fd,buf,WBUFW(buf,2));
+ return 0;
+}
+// ƒp[ƒeƒBƒƒ“ƒo’Η‰Α‰Β”Ϋ
+int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) {
+ WFIFOHEAD(fd, 15);
+ WFIFOW(fd,0) = 0x3822;
+ WFIFOL(fd,2) = party_id;
+ WFIFOL(fd,6) = account_id;
+ WFIFOL(fd,10) = char_id;
+ WFIFOB(fd,14) = flag;
+ WFIFOSET(fd,15);
+
+ return 0;
+}
+
+// ƒp[ƒeƒBέ’θ•ΟX’Κ’m
+int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag)
+{
+ unsigned char buf[16];
+ WBUFW(buf,0)=0x3823;
+ WBUFL(buf,2)=p->party_id;
+ WBUFL(buf,6)=account_id;
+ WBUFW(buf,10)=p->exp;
+ WBUFW(buf,12)=p->item;
+ WBUFB(buf,14)=flag;
+ if(flag==0)
+ mapif_sendall(buf,15);
+ else
+ mapif_send(fd,buf,15);
+ return 0;
+}
+
+//Checks whether the even-share setting of a party is broken when a character logs in. [Skotlex]
+int inter_party_logged(int party_id, int account_id, int char_id)
+{
+ struct party_data *p;
+ int i;
+
+ if (party_id <= 0)
+ return 0;
+
+ if (!party_id)
+ return 0;
+ p = inter_party_fromsql(party_id);
+ if(!p) //Non existant party?
+ return 0;
+
+ for(i = 0; i < MAX_PARTY; i++)
+ if(p->party.member[i].account_id==account_id &&
+ p->party.member[i].char_id==char_id)
+ {
+ if (!p->party.member[i].online) {
+ p->party.member[i].online = 1;
+ p->party.count++;
+ if(p->party.member[i].lv < p->min_lv ||
+ p->party.member[i].lv > p->max_lv)
+ int_party_check_lv(p);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// ƒp[ƒeƒB’E‘ή’Κ’m
+int mapif_party_leaved(int party_id,int account_id, int char_id) {
+ unsigned char buf[16];
+
+ WBUFW(buf,0) = 0x3824;
+ WBUFL(buf,2) = party_id;
+ WBUFL(buf,6) = account_id;
+ WBUFL(buf,10) = char_id;
+ mapif_sendall(buf, 14);
+ return 0;
+}
+
+// ƒp[ƒeƒBƒ}ƒbƒvXV’Κ’m
+int mapif_party_membermoved(struct party *p,int idx)
+{
+ unsigned char buf[20];
+
+ WBUFW(buf,0) = 0x3825;
+ WBUFL(buf,2) = p->party_id;
+ WBUFL(buf,6) = p->member[idx].account_id;
+ WBUFL(buf,10) = p->member[idx].char_id;
+ WBUFW(buf,14) = p->member[idx].map;
+ WBUFB(buf,16) = p->member[idx].online;
+ WBUFW(buf,17) = p->member[idx].lv;
+ mapif_sendall(buf, 19);
+ return 0;
+}
+
+// ƒp[ƒeƒB‰πŽU’Κ’m
+int mapif_party_broken(int party_id,int flag)
+{
+ unsigned char buf[16];
+ WBUFW(buf,0)=0x3826;
+ WBUFL(buf,2)=party_id;
+ WBUFB(buf,6)=flag;
+ mapif_sendall(buf,7);
+ //printf("int_party: broken %d\n",party_id);
+ return 0;
+}
+// ƒp[ƒeƒB“ΰ”­ŒΎ
+int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd)
+{
+ unsigned char buf[512];
+ WBUFW(buf,0)=0x3827;
+ WBUFW(buf,2)=len+12;
+ WBUFL(buf,4)=party_id;
+ WBUFL(buf,8)=account_id;
+ memcpy(WBUFP(buf,12),mes,len);
+ mapif_sendallwos(sfd, buf,len+12);
+ return 0;
+}
+
+//-------------------------------------------------------------------
+// map server‚©‚η‚̒ʐM
+
+
+// Create Party
+int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader)
+{
+ struct party_data *p;
+ int i;
+ if( (p=search_partyname(name))!=NULL){
+ mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
+ return 0;
+ }
+ // Check Authorised letters/symbols in the name of the character
+ if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+ for (i = 0; i < NAME_LENGTH && name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL) {
+ mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
+ return 0;
+ }
+ } else if (char_name_option == 2) { // 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) {
+ mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
+ return 0;
+ }
+ }
+
+ p= aCalloc(1, sizeof(struct party_data));
+
+ memcpy(p->party.name,name,NAME_LENGTH);
+ p->party.exp=0;
+ p->party.item=(item?1:0)|(item2?2:0);
+
+ memcpy(&p->party.member[0], leader, sizeof(struct party_member));
+ p->party.member[0].leader=1;
+ p->party.member[0].online=1;
+
+ p->party.party_id=-1;//New party.
+ if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) {
+ //Add party to db
+ int_party_calc_state(p);
+ idb_put(party_db_, p->party.party_id, p);
+ mapif_party_created(fd,leader->account_id,leader->char_id,&p->party);
+ mapif_party_info(fd,&p->party);
+ } else { //Failed to create party.
+ aFree(p);
+ mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
+ }
+
+ return 0;
+}
+// ƒp[ƒeƒBξ•ρ—v‹
+int mapif_parse_PartyInfo(int fd,int party_id)
+{
+ struct party_data *p;
+ p = inter_party_fromsql(party_id);
+
+ if (p)
+ mapif_party_info(fd,&p->party);
+ else
+ mapif_party_noinfo(fd,party_id);
+ return 0;
+}
+// ƒp[ƒeƒB’Η‰Α—v‹
+int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) {
+ struct party_data *p;
+ int i;
+
+ p = inter_party_fromsql(party_id);
+
+ if(!p || p->size == MAX_PARTY){
+ mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,1);
+ return 0;
+ }
+
+ for(i=0;i<MAX_PARTY;i++){
+ if(p->party.member[i].account_id)
+ continue;
+
+ memcpy(&p->party.member[i], member, sizeof(struct party_member));
+ p->party.member[i].leader=0;
+ if (p->party.member[i].online) p->party.count++;
+ p->size++;
+ if (p->size == 3) //Check family state.
+ int_party_calc_state(p);
+ else //Check even share range.
+ if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) {
+ if (p->family) p->family = 0; //Family state broken.
+ int_party_check_lv(p);
+ }
+
+ mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,0);
+ mapif_party_info(-1,&p->party);
+ inter_party_tosql(&p->party, PS_ADDMEMBER, i);
+ return 0;
+ }
+ //Party full
+ mapif_party_memberadded(fd,party_id,member->account_id,member->char_id,1);
+ return 0;
+}
+// ƒp[ƒeƒB[έ’θ•ΟX—v‹
+int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item)
+{
+ struct party_data *p;
+ int flag = 0;
+ p = inter_party_fromsql(party_id);
+
+ if(!p)
+ return 0;
+
+ p->party.exp=exp;
+ if( exp && !party_check_exp_share(p) ){
+ flag|=0x01;
+ p->party.exp=0;
+ }
+ p->party.item = item&0x3; //Filter out invalid values.
+ mapif_party_optionchanged(fd,&p->party,account_id,flag);
+ inter_party_tosql(&p->party, PS_BASIC, 0);
+ return 0;
+}
+// ƒp[ƒeƒB’E‘ή—v‹
+int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
+{
+ struct party_data *p;
+ int i,j=-1;
+
+ p = inter_party_fromsql(party_id);
+ if (!p) { //Party does not exists?
+ sprintf(tmp_sql, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return 0;
+ }
+
+ for (i = 0; i < MAX_PARTY; i++) {
+ if(p->party.member[i].account_id == account_id &&
+ p->party.member[i].char_id == char_id) {
+ break;
+ }
+ }
+ if (i >= MAX_PARTY)
+ return 0; //Member not found?
+
+ mapif_party_leaved(party_id, account_id, char_id);
+
+ if (p->party.member[i].leader){
+ p->party.member[i].account_id = 0;
+ for (j = 0; j < MAX_PARTY; j++) {
+ if (!p->party.member[j].account_id)
+ continue;
+ mapif_party_leaved(party_id, p->party.member[j].account_id, p->party.member[j].char_id);
+ p->party.member[j].account_id = 0;
+ }
+ //Party gets deleted on the check_empty call below.
+ } else {
+ inter_party_tosql(&p->party,PS_DELMEMBER,i);
+ j = p->party.member[i].lv;
+ if(p->party.member[i].online) p->party.count--;
+ memset(&p->party.member[i], 0, sizeof(struct party_member));
+ p->size--;
+ if (j == p->min_lv || j == p->max_lv || p->family)
+ {
+ if(p->family) p->family = 0; //Family state broken.
+ int_party_check_lv(p);
+ }
+ }
+
+ if (party_check_empty(p) == 0)
+ mapif_party_info(-1,&p->party);
+ return 0;
+}
+// When member goes to other map
+int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv)
+{
+ struct party_data *p;
+ int i;
+
+ p = inter_party_fromsql(party_id);
+ if (p == NULL)
+ return 0;
+
+ for(i = 0; i < MAX_PARTY; i++) {
+ if(p->party.member[i].account_id == account_id &&
+ p->party.member[i].char_id == char_id)
+ {
+ p->party.member[i].map = map;
+ if (p->party.member[i].online != online)
+ {
+ p->party.member[i].online = online;
+ if (online)
+ p->party.count++;
+ else
+ p->party.count--;
+ // Even share check situations: Family state (always breaks)
+ // character logging on/off is max/min level (update level range)
+ // or character logging on/off has a different level (update level range using new level)
+ if (p->family ||
+ (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) ||
+ (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv))
+ )
+ {
+ p->party.member[i].lv = lv;
+ int_party_check_lv(p);
+ }
+ }
+ if (p->party.member[i].lv != lv) {
+ if(p->party.member[i].lv == p->min_lv ||
+ p->party.member[i].lv == p->max_lv)
+ {
+ p->party.member[i].lv = lv;
+ int_party_check_lv(p);
+ } else
+ p->party.member[i].lv = lv;
+ }
+ mapif_party_membermoved(&p->party, i);
+ break;
+ }
+ }
+ return 0;
+}
+// ƒp[ƒeƒB‰πŽU—v‹
+int mapif_parse_BreakParty(int fd,int party_id)
+{
+ struct party_data *p;
+
+ p = inter_party_fromsql(party_id);
+
+ if(!p)
+ return 0;
+ inter_party_tosql(&p->party,PS_BREAK,0);
+ mapif_party_broken(fd,party_id);
+ return 0;
+}
+// ƒp[ƒeƒBƒƒbƒZ[ƒW‘—M
+int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len)
+{
+ return mapif_party_message(party_id,account_id,mes,len, fd);
+}
+// ƒp[ƒeƒBƒ`ƒFƒbƒN—v‹
+int mapif_parse_PartyCheck(int fd,int party_id,int account_id,int char_id)
+{
+ return party_check_conflict(party_id,account_id,char_id);
+}
+
+int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id)
+{
+ struct party_data *p;
+ int i;
+
+ p = inter_party_fromsql(party_id);
+
+ if(!p)
+ return 0;
+
+ for (i = 0; i < MAX_PARTY; i++)
+ {
+ if(p->party.member[i].leader)
+ p->party.member[i].leader = 0;
+ if(p->party.member[i].account_id == account_id &&
+ p->party.member[i].char_id == char_id)
+ {
+ p->party.member[i].leader = 1;
+ inter_party_tosql(&p->party,PS_LEADER, i);
+ }
+ }
+ return 1;
+}
+
+// map server ‚©‚η‚̒ʐM
+// E‚PƒpƒPƒbƒg‚Μ‚έ‰πΝ‚·‚ι‚±‚Ζ
+// EƒpƒPƒbƒg’·ƒf[ƒ^‚Νinter.c‚ΙƒZƒbƒg‚΅‚Δ‚¨‚­‚±‚Ζ
+// EƒpƒPƒbƒg’·ƒ`ƒFƒbƒN‚βARFIFOSKIP‚ΝŒΔ‚Ρo‚΅Œ³‚ōs‚ν‚κ‚ι‚̂ōs‚Α‚Δ‚Ν‚Θ‚η‚Θ‚’
+// EƒGƒ‰[‚Θ‚η0(false)A‚»‚€‚Ε‚Θ‚’‚Θ‚η1(true)‚π‚©‚¦‚³‚Θ‚―‚κ‚Ξ‚Θ‚η‚Θ‚’
+int inter_party_parse_frommap(int fd)
+{
+ RFIFOHEAD(fd);
+ switch(RFIFOW(fd,0)) {
+ case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break;
+ case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break;
+ case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break;
+ case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break;
+ case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
+ case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break;
+ case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break;
+ case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break;
+ case 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
+ case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+// ƒT[ƒo[‚©‚η’E‘ή—v‹iƒLƒƒƒ‰νœ—pj
+int inter_party_leave(int party_id,int account_id, int char_id)
+{
+ return mapif_parse_PartyLeave(-1,party_id,account_id, char_id);
+}
+
+int inter_party_CharOnline(int char_id, int party_id) {
+ struct party_data *p;
+ int i;
+
+ if (party_id == -1) {
+ //Get party_id from the database
+ sprintf (tmp_sql , "SELECT party_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if(sql_res == NULL)
+ return 0; //Eh? No party?
+
+ sql_row = mysql_fetch_row(sql_res);
+ party_id = sql_row?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+ }
+ if (party_id == 0)
+ return 0; //No party...
+
+ p = inter_party_fromsql(party_id);
+ if(!p) {
+ ShowError("Character %d's party %d not found!\n", char_id, party_id);
+ return 0;
+ }
+
+ //Set member online
+ for(i=0; i<MAX_PARTY; i++) {
+ if (p->party.member[i].char_id == char_id) {
+ if (!p->party.member[i].online) {
+ p->party.member[i].online = 1;
+ p->party.count++;
+ if (p->party.member[i].lv < p->min_lv ||
+ p->party.member[i].lv > p->max_lv)
+ int_party_check_lv(p);
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+int inter_party_CharOffline(int char_id, int party_id) {
+ struct party_data *p=NULL;
+ int i;
+
+ if (party_id == -1) {
+ //Get guild_id from the database
+ sprintf (tmp_sql , "SELECT party_id FROM `%s` WHERE char_id='%d'",char_db,char_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if(sql_res == NULL)
+ return 0; //Eh? No party?
+
+ sql_row = mysql_fetch_row(sql_res);
+ party_id = sql_row?atoi(sql_row[0]):0;
+ mysql_free_result(sql_res);
+ }
+ if (party_id == 0)
+ return 0; //No party...
+
+ //Character has a party, set character offline and check if they were the only member online
+ if ((p = inter_party_fromsql(party_id)) == NULL)
+ return 0;
+
+ //Set member offline
+ for(i=0; i< MAX_PARTY; i++) {
+ if(p->party.member[i].char_id == char_id)
+ {
+ p->party.member[i].online = 0;
+ p->party.count--;
+ if(p->party.member[i].lv == p->min_lv ||
+ p->party.member[i].lv == p->max_lv)
+ int_party_check_lv(p);
+ break;
+ }
+ }
+
+ if(!p->party.count)
+ //Parties don't have any data that needs be saved at this point... so just remove it from memory.
+ idb_remove(party_db_, party_id);
+ return 1;
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/int_party.h b/src/char_sql/int_party.h
index 7e6219f9c..4691447e9 100644
--- a/src/char_sql/int_party.h
+++ b/src/char_sql/int_party.h
@@ -1,30 +1,30 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _INT_PARTY_SQL_H_
-#define _INT_PARTY_SQL_H_
-
-//Party Flags on what to save/delete.
-//Create a new party entry (index holds leader's info)
-#define PS_CREATE 0x01
-//Update basic party info.
-#define PS_BASIC 0x02
-//Update party's leader
-#define PS_LEADER 0x04
-//Specify new party member (index specifies which party member)
-#define PS_ADDMEMBER 0x08
-//Specify member that left (index specifies which party member)
-#define PS_DELMEMBER 0x10
-//Specify that this party must be deleted.
-#define PS_BREAK 0x20
-
-int inter_party_parse_frommap(int fd);
-int inter_party_sql_init(void);
-void inter_party_sql_final(void);
-int inter_party_leave(int party_id,int account_id, int char_id);
-int inter_party_logged(int party_id, int account_id, int char_id);
-int inter_party_CharOnline(int char_id, int party_id);
-int inter_party_CharOffline(int char_id, int party_id);
-//Required for the TXT->SQL converter
-int inter_party_tosql(struct party *p, int flag, int index);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_PARTY_SQL_H_
+#define _INT_PARTY_SQL_H_
+
+//Party Flags on what to save/delete.
+//Create a new party entry (index holds leader's info)
+#define PS_CREATE 0x01
+//Update basic party info.
+#define PS_BASIC 0x02
+//Update party's leader
+#define PS_LEADER 0x04
+//Specify new party member (index specifies which party member)
+#define PS_ADDMEMBER 0x08
+//Specify member that left (index specifies which party member)
+#define PS_DELMEMBER 0x10
+//Specify that this party must be deleted.
+#define PS_BREAK 0x20
+
+int inter_party_parse_frommap(int fd);
+int inter_party_sql_init(void);
+void inter_party_sql_final(void);
+int inter_party_leave(int party_id,int account_id, int char_id);
+int inter_party_logged(int party_id, int account_id, int char_id);
+int inter_party_CharOnline(int char_id, int party_id);
+int inter_party_CharOffline(int char_id, int party_id);
+//Required for the TXT->SQL converter
+int inter_party_tosql(struct party *p, int flag, int index);
+#endif
diff --git a/src/char_sql/int_pet.c b/src/char_sql/int_pet.c
index 69eb4ec02..ff4f0edb9 100644
--- a/src/char_sql/int_pet.c
+++ b/src/char_sql/int_pet.c
@@ -1,372 +1,372 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by Jioh L. Jung
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "char.h"
-#include "../common/strlib.h"
-#include "../common/showmsg.h"
-
-struct s_pet *pet_pt;
-
-#ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
-#else
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-#endif
-
-//---------------------------------------------------------
-int inter_pet_tosql(int pet_id, struct s_pet *p) {
- //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`)
- char t_name[NAME_LENGTH*2];
-
- jstrescapecpy(t_name, p->name);
-
- if(p->hungry < 0)
- p->hungry = 0;
- else if(p->hungry > 100)
- p->hungry = 100;
- if(p->intimate < 0)
- p->intimate = 0;
- else if(p->intimate > 1000)
- p->intimate = 1000;
- if (pet_id == -1) //New pet.
- sprintf(tmp_sql,"INSERT INTO `%s` "
- "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) "
- "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
- pet_db, p->class_, t_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate);
-
- else //Update pet.
- sprintf(tmp_sql, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'",
- pet_db, p->class_, t_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- } else if (pet_id == -1) { //New pet inserted.
- if(mysql_field_count(&mysql_handle) == 0 &&
- mysql_insert_id(&mysql_handle) != 0) {
- p->pet_id = pet_id = (int)mysql_insert_id(&mysql_handle);
- } else {
- ShowError("inter_pet_tosql: Failed to retrieve new pet_id for '%s'. Pet creation aborted.\n", p->name);
- return 0;
- }
- }
-
- if (save_log)
- ShowInfo("Pet saved %d - %s.\n", pet_id, p->name);
- return 1;
-}
-#ifndef TXT_SQL_CONVERT
-int inter_pet_fromsql(int pet_id, struct s_pet *p){
-
-#ifdef NOISY
- ShowInfo("Loading pet (%d)...\n",pet_id);
-#endif
- memset(p, 0, sizeof(struct s_pet));
-
- //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`)
-
- sprintf(tmp_sql,"SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'",pet_db, pet_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return 0;
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
- sql_row = mysql_fetch_row(sql_res);
-
- p->pet_id = pet_id;
- p->class_ = atoi(sql_row[1]);
- memcpy(p->name, sql_row[2],NAME_LENGTH-1);
- p->account_id = atoi(sql_row[3]);
- p->char_id = atoi(sql_row[4]);
- p->level = atoi(sql_row[5]);
- p->egg_id = atoi(sql_row[6]);
- p->equip = atoi(sql_row[7]);
- p->intimate = atoi(sql_row[8]);
- p->hungry = atoi(sql_row[9]);
- p->rename_flag = atoi(sql_row[10]);
- p->incuvate = atoi(sql_row[11]);
- }
- if(p->hungry < 0)
- p->hungry = 0;
- else if(p->hungry > 100)
- p->hungry = 100;
- if(p->intimate < 0)
- p->intimate = 0;
- else if(p->intimate > 1000)
- p->intimate = 1000;
-
- mysql_free_result(sql_res);
-
- if (save_log)
- ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name);
- return 0;
-}
-//----------------------------------------------
-
-int inter_pet_sql_init(void){
- //memory alloc
- pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1);
- return 0;
-}
-void inter_pet_sql_final(void){
- if (pet_pt) aFree(pet_pt);
- return;
-}
-//----------------------------------
-int inter_pet_delete(int pet_id){
- ShowInfo("delete pet request: %d...\n",pet_id);
-
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `pet_id`='%d'",pet_db, pet_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return 0;
-}
-//------------------------------------------------------
-int mapif_pet_created(int fd, int account_id, struct s_pet *p)
-{
- WFIFOHEAD(fd, 11);
- WFIFOW(fd, 0) =0x3880;
- WFIFOL(fd, 2) =account_id;
- if(p!=NULL){
- WFIFOB(fd, 6)=0;
- WFIFOL(fd, 7) =p->pet_id;
- ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name);
- }else{
- WFIFOB(fd, 6)=1;
- WFIFOL(fd, 7)=0;
- }
- WFIFOSET(fd, 11);
-
- return 0;
-}
-
-int mapif_pet_info(int fd, int account_id, struct s_pet *p){
- WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
- WFIFOW(fd, 0) =0x3881;
- WFIFOW(fd, 2) =sizeof(struct s_pet) + 9;
- WFIFOL(fd, 4) =account_id;
- WFIFOB(fd, 8)=0;
- memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet));
- WFIFOSET(fd, WFIFOW(fd, 2));
-
- return 0;
-}
-
-int mapif_pet_noinfo(int fd, int account_id){
- WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
- WFIFOW(fd, 0) =0x3881;
- WFIFOW(fd, 2) =sizeof(struct s_pet) + 9;
- WFIFOL(fd, 4) =account_id;
- WFIFOB(fd, 8)=1;
- memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet));
- WFIFOSET(fd, WFIFOW(fd, 2));
-
- return 0;
-}
-
-int mapif_save_pet_ack(int fd, int account_id, int flag){
- WFIFOHEAD(fd, 7);
- WFIFOW(fd, 0) =0x3882;
- WFIFOL(fd, 2) =account_id;
- WFIFOB(fd, 6) =flag;
- WFIFOSET(fd, 7);
-
- return 0;
-}
-
-int mapif_delete_pet_ack(int fd, int flag){
- WFIFOHEAD(fd, 3);
- WFIFOW(fd, 0) =0x3883;
- WFIFOB(fd, 2) =flag;
- WFIFOSET(fd, 3);
-
- return 0;
-}
-
-int mapif_rename_pet_ack(int fd, int account_id, int char_id, int flag, char *name){
- WFIFOHEAD(fd, NAME_LENGTH+12);
- WFIFOW(fd, 0) =0x3884;
- WFIFOL(fd, 2) =account_id;
- WFIFOL(fd, 6) =char_id;
- WFIFOB(fd, 10) =flag;
- memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
- WFIFOSET(fd, NAME_LENGTH+12);
-
- return 0;
-}
-
-
-int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short pet_lv, short pet_egg_id,
- short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name){
-
- memset(pet_pt, 0, sizeof(struct s_pet));
- memcpy(pet_pt->name, pet_name, NAME_LENGTH-1);
- if(incuvate == 1)
- pet_pt->account_id = pet_pt->char_id = 0;
- else {
- pet_pt->account_id = account_id;
- pet_pt->char_id = char_id;
- }
- pet_pt->class_ = pet_class;
- pet_pt->level = pet_lv;
- pet_pt->egg_id = pet_egg_id;
- pet_pt->equip = pet_equip;
- pet_pt->intimate = intimate;
- pet_pt->hungry = hungry;
- pet_pt->rename_flag = rename_flag;
- pet_pt->incuvate = incuvate;
-
- if(pet_pt->hungry < 0)
- pet_pt->hungry = 0;
- else if(pet_pt->hungry > 100)
- pet_pt->hungry = 100;
- if(pet_pt->intimate < 0)
- pet_pt->intimate = 0;
- else if(pet_pt->intimate > 1000)
- pet_pt->intimate = 1000;
-
- pet_pt->pet_id = -1; //Signal NEW pet.
- if (inter_pet_tosql(pet_pt->pet_id,pet_pt))
- mapif_pet_created(fd, account_id, pet_pt);
- else //Failed...
- mapif_pet_created(fd, account_id, NULL);
-
- return 0;
-}
-
-int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){
- memset(pet_pt, 0, sizeof(struct s_pet));
-
- inter_pet_fromsql(pet_id, pet_pt);
-
- if(pet_pt!=NULL) {
- if(pet_pt->incuvate == 1) {
- pet_pt->account_id = pet_pt->char_id = 0;
- mapif_pet_info(fd, account_id, pet_pt);
- }
- else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id)
- mapif_pet_info(fd, account_id, pet_pt);
- else
- mapif_pet_noinfo(fd, account_id);
- }
- else
- mapif_pet_noinfo(fd, account_id);
-
- return 0;
-}
-
-int mapif_save_pet(int fd, int account_id, struct s_pet *data) {
- //here process pet save request.
- int len;
- RFIFOHEAD(fd);
- len=RFIFOW(fd, 2);
- if(sizeof(struct s_pet)!=len-8) {
- ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8);
- }
-
- else{
- if(data->hungry < 0)
- data->hungry = 0;
- else if(data->hungry > 100)
- data->hungry = 100;
- if(data->intimate < 0)
- data->intimate = 0;
- else if(data->intimate > 1000)
- data->intimate = 1000;
- inter_pet_tosql(data->pet_id,data);
- mapif_save_pet_ack(fd, account_id, 0);
- }
-
- return 0;
-}
-
-int mapif_delete_pet(int fd, int pet_id){
- mapif_delete_pet_ack(fd, inter_pet_delete(pet_id));
-
- return 0;
-}
-
-int mapif_rename_pet(int fd, int account_id, int char_id, char *name){
- int i;
-
- // Check Authorised letters/symbols in the name of the pet
- if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
- for (i = 0; i < NAME_LENGTH && name[i]; i++)
- if (strchr(char_name_letters, name[i]) == NULL) {
- mapif_rename_pet_ack(fd, account_id, char_id, 0, name);
- return 0;
- }
- } else if (char_name_option == 2) { // 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) {
- mapif_rename_pet_ack(fd, account_id, char_id, 0, name);
- return 0;
- }
- }
-
- mapif_rename_pet_ack(fd, account_id, char_id, 1, name);
- return 0;
-}
-
-int mapif_parse_CreatePet(int fd){
- RFIFOHEAD(fd);
- mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18),
- RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24));
- return 0;
-}
-
-int mapif_parse_LoadPet(int fd){
- RFIFOHEAD(fd);
- mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10));
- return 0;
-}
-
-int mapif_parse_SavePet(int fd){
- RFIFOHEAD(fd);
- mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8));
- return 0;
-}
-
-int mapif_parse_DeletePet(int fd){
- RFIFOHEAD(fd);
- mapif_delete_pet(fd, RFIFOL(fd, 2));
- return 0;
-}
-
-int mapif_parse_RenamePet(int fd){
- RFIFOHEAD(fd);
- mapif_rename_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10));
- return 0;
-}
-
-int inter_pet_parse_frommap(int fd){
- RFIFOHEAD(fd);
- switch(RFIFOW(fd, 0)){
- case 0x3080: mapif_parse_CreatePet(fd); break;
- case 0x3081: mapif_parse_LoadPet(fd); break;
- case 0x3082: mapif_parse_SavePet(fd); break;
- case 0x3083: mapif_parse_DeletePet(fd); break;
- case 0x3084: mapif_parse_RenamePet(fd); break;
- default:
- return 0;
- }
- return 1;
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by Jioh L. Jung
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "char.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+
+struct s_pet *pet_pt;
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+//---------------------------------------------------------
+int inter_pet_tosql(int pet_id, struct s_pet *p) {
+ //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`)
+ char t_name[NAME_LENGTH*2];
+
+ jstrescapecpy(t_name, p->name);
+
+ if(p->hungry < 0)
+ p->hungry = 0;
+ else if(p->hungry > 100)
+ p->hungry = 100;
+ if(p->intimate < 0)
+ p->intimate = 0;
+ else if(p->intimate > 1000)
+ p->intimate = 1000;
+ if (pet_id == -1) //New pet.
+ sprintf(tmp_sql,"INSERT INTO `%s` "
+ "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) "
+ "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ pet_db, p->class_, t_name, p->account_id, p->char_id, p->level, p->egg_id,
+ p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate);
+
+ else //Update pet.
+ sprintf(tmp_sql, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'",
+ pet_db, p->class_, t_name, p->account_id, p->char_id, p->level, p->egg_id,
+ p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ } else if (pet_id == -1) { //New pet inserted.
+ if(mysql_field_count(&mysql_handle) == 0 &&
+ mysql_insert_id(&mysql_handle) != 0) {
+ p->pet_id = pet_id = (int)mysql_insert_id(&mysql_handle);
+ } else {
+ ShowError("inter_pet_tosql: Failed to retrieve new pet_id for '%s'. Pet creation aborted.\n", p->name);
+ return 0;
+ }
+ }
+
+ if (save_log)
+ ShowInfo("Pet saved %d - %s.\n", pet_id, p->name);
+ return 1;
+}
+#ifndef TXT_SQL_CONVERT
+int inter_pet_fromsql(int pet_id, struct s_pet *p){
+
+#ifdef NOISY
+ ShowInfo("Loading pet (%d)...\n",pet_id);
+#endif
+ memset(p, 0, sizeof(struct s_pet));
+
+ //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`)
+
+ sprintf(tmp_sql,"SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'",pet_db, pet_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+
+ p->pet_id = pet_id;
+ p->class_ = atoi(sql_row[1]);
+ memcpy(p->name, sql_row[2],NAME_LENGTH-1);
+ p->account_id = atoi(sql_row[3]);
+ p->char_id = atoi(sql_row[4]);
+ p->level = atoi(sql_row[5]);
+ p->egg_id = atoi(sql_row[6]);
+ p->equip = atoi(sql_row[7]);
+ p->intimate = atoi(sql_row[8]);
+ p->hungry = atoi(sql_row[9]);
+ p->rename_flag = atoi(sql_row[10]);
+ p->incuvate = atoi(sql_row[11]);
+ }
+ if(p->hungry < 0)
+ p->hungry = 0;
+ else if(p->hungry > 100)
+ p->hungry = 100;
+ if(p->intimate < 0)
+ p->intimate = 0;
+ else if(p->intimate > 1000)
+ p->intimate = 1000;
+
+ mysql_free_result(sql_res);
+
+ if (save_log)
+ ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name);
+ return 0;
+}
+//----------------------------------------------
+
+int inter_pet_sql_init(void){
+ //memory alloc
+ pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1);
+ return 0;
+}
+void inter_pet_sql_final(void){
+ if (pet_pt) aFree(pet_pt);
+ return;
+}
+//----------------------------------
+int inter_pet_delete(int pet_id){
+ ShowInfo("delete pet request: %d...\n",pet_id);
+
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `pet_id`='%d'",pet_db, pet_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return 0;
+}
+//------------------------------------------------------
+int mapif_pet_created(int fd, int account_id, struct s_pet *p)
+{
+ WFIFOHEAD(fd, 11);
+ WFIFOW(fd, 0) =0x3880;
+ WFIFOL(fd, 2) =account_id;
+ if(p!=NULL){
+ WFIFOB(fd, 6)=0;
+ WFIFOL(fd, 7) =p->pet_id;
+ ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name);
+ }else{
+ WFIFOB(fd, 6)=1;
+ WFIFOL(fd, 7)=0;
+ }
+ WFIFOSET(fd, 11);
+
+ return 0;
+}
+
+int mapif_pet_info(int fd, int account_id, struct s_pet *p){
+ WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
+ WFIFOW(fd, 0) =0x3881;
+ WFIFOW(fd, 2) =sizeof(struct s_pet) + 9;
+ WFIFOL(fd, 4) =account_id;
+ WFIFOB(fd, 8)=0;
+ memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet));
+ WFIFOSET(fd, WFIFOW(fd, 2));
+
+ return 0;
+}
+
+int mapif_pet_noinfo(int fd, int account_id){
+ WFIFOHEAD(fd, sizeof(struct s_pet) + 9);
+ WFIFOW(fd, 0) =0x3881;
+ WFIFOW(fd, 2) =sizeof(struct s_pet) + 9;
+ WFIFOL(fd, 4) =account_id;
+ WFIFOB(fd, 8)=1;
+ memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet));
+ WFIFOSET(fd, WFIFOW(fd, 2));
+
+ return 0;
+}
+
+int mapif_save_pet_ack(int fd, int account_id, int flag){
+ WFIFOHEAD(fd, 7);
+ WFIFOW(fd, 0) =0x3882;
+ WFIFOL(fd, 2) =account_id;
+ WFIFOB(fd, 6) =flag;
+ WFIFOSET(fd, 7);
+
+ return 0;
+}
+
+int mapif_delete_pet_ack(int fd, int flag){
+ WFIFOHEAD(fd, 3);
+ WFIFOW(fd, 0) =0x3883;
+ WFIFOB(fd, 2) =flag;
+ WFIFOSET(fd, 3);
+
+ return 0;
+}
+
+int mapif_rename_pet_ack(int fd, int account_id, int char_id, int flag, char *name){
+ WFIFOHEAD(fd, NAME_LENGTH+12);
+ WFIFOW(fd, 0) =0x3884;
+ WFIFOL(fd, 2) =account_id;
+ WFIFOL(fd, 6) =char_id;
+ WFIFOB(fd, 10) =flag;
+ memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
+ WFIFOSET(fd, NAME_LENGTH+12);
+
+ return 0;
+}
+
+
+int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short pet_lv, short pet_egg_id,
+ short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name){
+
+ memset(pet_pt, 0, sizeof(struct s_pet));
+ memcpy(pet_pt->name, pet_name, NAME_LENGTH-1);
+ if(incuvate == 1)
+ pet_pt->account_id = pet_pt->char_id = 0;
+ else {
+ pet_pt->account_id = account_id;
+ pet_pt->char_id = char_id;
+ }
+ pet_pt->class_ = pet_class;
+ pet_pt->level = pet_lv;
+ pet_pt->egg_id = pet_egg_id;
+ pet_pt->equip = pet_equip;
+ pet_pt->intimate = intimate;
+ pet_pt->hungry = hungry;
+ pet_pt->rename_flag = rename_flag;
+ pet_pt->incuvate = incuvate;
+
+ if(pet_pt->hungry < 0)
+ pet_pt->hungry = 0;
+ else if(pet_pt->hungry > 100)
+ pet_pt->hungry = 100;
+ if(pet_pt->intimate < 0)
+ pet_pt->intimate = 0;
+ else if(pet_pt->intimate > 1000)
+ pet_pt->intimate = 1000;
+
+ pet_pt->pet_id = -1; //Signal NEW pet.
+ if (inter_pet_tosql(pet_pt->pet_id,pet_pt))
+ mapif_pet_created(fd, account_id, pet_pt);
+ else //Failed...
+ mapif_pet_created(fd, account_id, NULL);
+
+ return 0;
+}
+
+int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){
+ memset(pet_pt, 0, sizeof(struct s_pet));
+
+ inter_pet_fromsql(pet_id, pet_pt);
+
+ if(pet_pt!=NULL) {
+ if(pet_pt->incuvate == 1) {
+ pet_pt->account_id = pet_pt->char_id = 0;
+ mapif_pet_info(fd, account_id, pet_pt);
+ }
+ else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id)
+ mapif_pet_info(fd, account_id, pet_pt);
+ else
+ mapif_pet_noinfo(fd, account_id);
+ }
+ else
+ mapif_pet_noinfo(fd, account_id);
+
+ return 0;
+}
+
+int mapif_save_pet(int fd, int account_id, struct s_pet *data) {
+ //here process pet save request.
+ int len;
+ RFIFOHEAD(fd);
+ len=RFIFOW(fd, 2);
+ if(sizeof(struct s_pet)!=len-8) {
+ ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8);
+ }
+
+ else{
+ if(data->hungry < 0)
+ data->hungry = 0;
+ else if(data->hungry > 100)
+ data->hungry = 100;
+ if(data->intimate < 0)
+ data->intimate = 0;
+ else if(data->intimate > 1000)
+ data->intimate = 1000;
+ inter_pet_tosql(data->pet_id,data);
+ mapif_save_pet_ack(fd, account_id, 0);
+ }
+
+ return 0;
+}
+
+int mapif_delete_pet(int fd, int pet_id){
+ mapif_delete_pet_ack(fd, inter_pet_delete(pet_id));
+
+ return 0;
+}
+
+int mapif_rename_pet(int fd, int account_id, int char_id, char *name){
+ int i;
+
+ // Check Authorised letters/symbols in the name of the pet
+ if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+ for (i = 0; i < NAME_LENGTH && name[i]; i++)
+ if (strchr(char_name_letters, name[i]) == NULL) {
+ mapif_rename_pet_ack(fd, account_id, char_id, 0, name);
+ return 0;
+ }
+ } else if (char_name_option == 2) { // 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) {
+ mapif_rename_pet_ack(fd, account_id, char_id, 0, name);
+ return 0;
+ }
+ }
+
+ mapif_rename_pet_ack(fd, account_id, char_id, 1, name);
+ return 0;
+}
+
+int mapif_parse_CreatePet(int fd){
+ RFIFOHEAD(fd);
+ mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18),
+ RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24));
+ return 0;
+}
+
+int mapif_parse_LoadPet(int fd){
+ RFIFOHEAD(fd);
+ mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10));
+ return 0;
+}
+
+int mapif_parse_SavePet(int fd){
+ RFIFOHEAD(fd);
+ mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8));
+ return 0;
+}
+
+int mapif_parse_DeletePet(int fd){
+ RFIFOHEAD(fd);
+ mapif_delete_pet(fd, RFIFOL(fd, 2));
+ return 0;
+}
+
+int mapif_parse_RenamePet(int fd){
+ RFIFOHEAD(fd);
+ mapif_rename_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10));
+ return 0;
+}
+
+int inter_pet_parse_frommap(int fd){
+ RFIFOHEAD(fd);
+ switch(RFIFOW(fd, 0)){
+ case 0x3080: mapif_parse_CreatePet(fd); break;
+ case 0x3081: mapif_parse_LoadPet(fd); break;
+ case 0x3082: mapif_parse_SavePet(fd); break;
+ case 0x3083: mapif_parse_DeletePet(fd); break;
+ case 0x3084: mapif_parse_RenamePet(fd); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/int_pet.h b/src/char_sql/int_pet.h
index fa5cbac0d..1b03c9768 100644
--- a/src/char_sql/int_pet.h
+++ b/src/char_sql/int_pet.h
@@ -1,18 +1,18 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _INT_PET_SQL_H_
-#define _INT_PET_SQL_H_
-
-int inter_pet_init(void);
-void inter_pet_sql_final(void);
-int inter_pet_save(void);
-int inter_pet_delete(int pet_id);
-
-int inter_pet_parse_frommap(int fd);
-int inter_pet_sql_init(void);
-//extern char pet_txt[256];
-
-//Exported for use in the TXT-SQL converter.
-int inter_pet_tosql(int pet_id, struct s_pet *p);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_PET_SQL_H_
+#define _INT_PET_SQL_H_
+
+int inter_pet_init(void);
+void inter_pet_sql_final(void);
+int inter_pet_save(void);
+int inter_pet_delete(int pet_id);
+
+int inter_pet_parse_frommap(int fd);
+int inter_pet_sql_init(void);
+//extern char pet_txt[256];
+
+//Exported for use in the TXT-SQL converter.
+int inter_pet_tosql(int pet_id, struct s_pet *p);
+#endif
diff --git a/src/char_sql/int_storage.c b/src/char_sql/int_storage.c
index 578de6bc8..5ca2c25bb 100644
--- a/src/char_sql/int_storage.c
+++ b/src/char_sql/int_storage.c
@@ -1,379 +1,379 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by Jioh L. Jung
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "char.h"
-#include "itemdb.h"
-#include "../common/showmsg.h"
-
-#define STORAGE_MEMINC 16
-
-#ifndef TXT_SQL_CONVERT
-// reset by inter_config_read()
-struct storage *storage_pt=NULL;
-struct guild_storage *guild_storage_pt=NULL;
-
-#ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
-#else
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
-#endif
-
-#endif //TXT_SQL_CONVERT
-// storage data -> DB conversion
-int storage_tosql(int account_id,struct storage *p){
- int i,j;
-// int eqcount=1;
-// int noteqcount=1;
- int count=0;
- struct itemtmp mapitem[MAX_STORAGE];
- for(i=0;i<MAX_STORAGE;i++){
- if(p->storage_[i].nameid>0){
- mapitem[count].flag=0;
- mapitem[count].id = p->storage_[i].id;
- mapitem[count].nameid=p->storage_[i].nameid;
- mapitem[count].amount = p->storage_[i].amount;
- mapitem[count].equip = p->storage_[i].equip;
- mapitem[count].identify = p->storage_[i].identify;
- mapitem[count].refine = p->storage_[i].refine;
- mapitem[count].attribute = p->storage_[i].attribute;
- for(j=0; j<MAX_SLOTS; j++)
- mapitem[count].card[j] = p->storage_[i].card[j];
- count++;
- }
- }
-
- memitemdata_to_sql(mapitem, count, account_id,TABLE_STORAGE);
-
- //printf ("storage dump to DB - id: %d (total: %d)\n", account_id, j);
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-
-// DB -> storage data conversion
-int storage_fromsql(int account_id, struct storage *p){
- int i=0,j;
- char * str_p = tmp_sql;
-
- memset(p,0,sizeof(struct storage)); //clean up memory
- p->storage_amount = 0;
- p->account_id = account_id;
-
- // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
- str_p += sprintf(str_p,"SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`");
-
- for (j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`", j);
-
- str_p += sprintf(str_p," FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id);
-
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle) ;
-
- if (sql_res) {
- while((sql_row = mysql_fetch_row(sql_res)) && i<MAX_STORAGE) { //start to fetch
- p->storage_[i].id= atoi(sql_row[0]);
- p->storage_[i].nameid= atoi(sql_row[1]);
- p->storage_[i].amount= atoi(sql_row[2]);
- p->storage_[i].equip= atoi(sql_row[3]);
- p->storage_[i].identify= atoi(sql_row[4]);
- p->storage_[i].refine= atoi(sql_row[5]);
- p->storage_[i].attribute= atoi(sql_row[6]);
- for (j=0; j<MAX_SLOTS; j++)
- p->storage_[i].card[j]= atoi(sql_row[7+j]);
- i++;
- }
- p->storage_amount = i;
- mysql_free_result(sql_res);
- }
-
- ShowInfo ("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount);
- return 1;
-}
-#endif //TXT_SQL_CONVERT
-// Save guild_storage data to sql
-int guild_storage_tosql(int guild_id, struct guild_storage *p){
- int i,j;
-// int eqcount=1;
-// int noteqcount=1;
- int count=0;
- struct itemtmp mapitem[MAX_GUILD_STORAGE];
- for(i=0;i<MAX_GUILD_STORAGE;i++){
- if(p->storage_[i].nameid>0){
- mapitem[count].flag=0;
- mapitem[count].id = p->storage_[i].id;
- mapitem[count].nameid=p->storage_[i].nameid;
- mapitem[count].amount = p->storage_[i].amount;
- mapitem[count].equip = p->storage_[i].equip;
- mapitem[count].identify = p->storage_[i].identify;
- mapitem[count].refine = p->storage_[i].refine;
- mapitem[count].attribute = p->storage_[i].attribute;
- for (j=0; j<MAX_SLOTS; j++)
- mapitem[count].card[j] = p->storage_[i].card[j];
- count++;
- }
- }
-
- memitemdata_to_sql(mapitem, count, guild_id,TABLE_GUILD_STORAGE);
-
- ShowInfo ("guild storage save to DB - id: %d (total: %d)\n", guild_id,i);
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-// Load guild_storage data to mem
-int guild_storage_fromsql(int guild_id, struct guild_storage *p){
- int i=0,j;
- struct guild_storage *gs=guild_storage_pt;
- char * str_p = tmp_sql;
- p=gs;
-
- memset(p,0,sizeof(struct guild_storage)); //clean up memory
- p->storage_amount = 0;
- p->guild_id = guild_id;
-
- // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
- str_p += sprintf(str_p,"SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`");
-
- for (j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p, ", `card%d`", j);
-
- str_p += sprintf(str_p," FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id);
-
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle) ;
-
- if (sql_res) {
- while((sql_row = mysql_fetch_row(sql_res)) && i < MAX_GUILD_STORAGE) { //start to fetch
- p->storage_[i].id= atoi(sql_row[0]);
- p->storage_[i].nameid= atoi(sql_row[1]);
- p->storage_[i].amount= atoi(sql_row[2]);
- p->storage_[i].equip= atoi(sql_row[3]);
- p->storage_[i].identify= atoi(sql_row[4]);
- p->storage_[i].refine= atoi(sql_row[5]);
- p->storage_[i].attribute= atoi(sql_row[6]);
- for (j=0; j<MAX_SLOTS; j++)
- p->storage_[i].card[j] = atoi(sql_row[7+j]);
- i++;
- }
- p->storage_amount = i;
- mysql_free_result(sql_res);
- }
- ShowInfo ("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount);
- return 0;
-}
-
-//---------------------------------------------------------
-// storage data initialize
-int inter_storage_sql_init(void){
-
- //memory alloc
- ShowDebug("interserver storage memory initialize....(%d byte)\n",sizeof(struct storage));
- storage_pt = (struct storage*)aCalloc(sizeof(struct storage), 1);
- guild_storage_pt = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1);
-// memset(storage_pt,0,sizeof(struct storage)); //Calloc sets stuff to 0 already. [Skotlex]
-// memset(guild_storage_pt,0,sizeof(struct guild_storage));
-
- return 1;
-}
-// storage data finalize
-void inter_storage_sql_final(void)
-{
- if (storage_pt) aFree(storage_pt);
- if (guild_storage_pt) aFree(guild_storage_pt);
- return;
-}
-// q?f[^?
-int inter_storage_delete(int account_id)
-{
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id`='%d'",storage_db, account_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return 0;
-}
-int inter_guild_storage_delete(int guild_id)
-{
- sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_storage_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- return 0;
-}
-
-//---------------------------------------------------------
-// packet from map server
-
-// recive packet about storage data
-int mapif_load_storage(int fd,int account_id){
- //load from DB
- WFIFOHEAD(fd, sizeof(struct storage)+8);
- storage_fromsql(account_id, storage_pt);
- WFIFOW(fd,0)=0x3810;
- WFIFOW(fd,2)=sizeof(struct storage)+8;
- WFIFOL(fd,4)=account_id;
- memcpy(WFIFOP(fd,8),storage_pt,sizeof(struct storage));
- WFIFOSET(fd,WFIFOW(fd,2));
- return 0;
-}
-// send ack to map server which is "storage data save ok."
-int mapif_save_storage_ack(int fd,int account_id){
- WFIFOHEAD(fd, 7);
- WFIFOW(fd,0)=0x3811;
- WFIFOL(fd,2)=account_id;
- WFIFOB(fd,6)=0;
- WFIFOSET(fd,7);
- return 0;
-}
-
-int mapif_load_guild_storage(int fd,int account_id,int guild_id)
-{
- int guild_exist=1;
- WFIFOHEAD(fd, sizeof(struct guild_storage)+12);
- WFIFOW(fd,0)=0x3818;
-
-#if 0 // innodb guilds should render this check unnecessary [Aru]
- // Check if guild exists, I may write a function for this later, coz I use it several times.
- //printf("- Check if guild %d exists\n",g->guild_id);
- sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
- sql_row = mysql_fetch_row(sql_res);
- guild_exist = atoi (sql_row[0]);
- //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes"));
- }
- mysql_free_result(sql_res) ; //resource free
-#endif
- if(guild_exist==1) {
- guild_storage_fromsql(guild_id,guild_storage_pt);
- WFIFOW(fd,2)=sizeof(struct guild_storage)+12;
- WFIFOL(fd,4)=account_id;
- WFIFOL(fd,8)=guild_id;
- memcpy(WFIFOP(fd,12),guild_storage_pt,sizeof(struct guild_storage));
- }
- else {
- WFIFOW(fd,2)=12;
- WFIFOL(fd,4)=account_id;
- WFIFOL(fd,8)=0;
- }
- WFIFOSET(fd,WFIFOW(fd,2));
-
- return 0;
-}
-int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail)
-{
- WFIFOHEAD(fd,11);
- WFIFOW(fd,0)=0x3819;
- WFIFOL(fd,2)=account_id;
- WFIFOL(fd,6)=guild_id;
- WFIFOB(fd,10)=fail;
- WFIFOSET(fd,11);
- return 0;
-}
-
-//---------------------------------------------------------
-// packet from map server
-
-// recive request about storage data
-int mapif_parse_LoadStorage(int fd){
- RFIFOHEAD(fd);
- mapif_load_storage(fd,RFIFOL(fd,2));
- return 0;
-}
-// storage data recive and save
-int mapif_parse_SaveStorage(int fd){
- int account_id;
- int len;
- RFIFOHEAD(fd);
- account_id=RFIFOL(fd,4);
- len=RFIFOW(fd,2);
- if(sizeof(struct storage)!=len-8){
- ShowError("inter storage: data size error %d %d\n",sizeof(struct storage),len-8);
- }else{
- memcpy(&storage_pt[0],RFIFOP(fd,8),sizeof(struct storage));
- storage_tosql(account_id, storage_pt);
- mapif_save_storage_ack(fd,account_id);
- }
- return 0;
-}
-
-int mapif_parse_LoadGuildStorage(int fd)
-{
- RFIFOHEAD(fd);
- mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6));
- return 0;
-}
-
-int mapif_parse_SaveGuildStorage(int fd)
-{
- int guild_exist=1;
- int guild_id;
- int len;
- RFIFOHEAD(fd);
- guild_id=RFIFOL(fd,8);
- len=RFIFOW(fd,2);
- if(sizeof(struct guild_storage)!=len-12){
- ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12);
- }
- else {
-#if 0 // Again, innodb key checks make the check pointless
- // Check if guild exists, I may write a function for this later, coz I use it several times.
- //printf("- Check if guild %d exists\n",g->guild_id);
- sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle) ;
- if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
- sql_row = mysql_fetch_row(sql_res);
- guild_exist = atoi (sql_row[0]);
- //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes"));
- }
- mysql_free_result(sql_res) ; //resource free
-#endif
- if(guild_exist==1) {
- memcpy(guild_storage_pt,RFIFOP(fd,12),sizeof(struct guild_storage));
- guild_storage_tosql(guild_id,guild_storage_pt);
- mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0);
- }
- else
- mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1);
- }
- return 0;
-}
-
-
-int inter_storage_parse_frommap(int fd){
- RFIFOHEAD(fd);
- switch(RFIFOW(fd,0)){
- case 0x3010: mapif_parse_LoadStorage(fd); break;
- case 0x3011: mapif_parse_SaveStorage(fd); break;
- case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
- case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
- default:
- return 0;
- }
- return 1;
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by Jioh L. Jung
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "char.h"
+#include "itemdb.h"
+#include "../common/showmsg.h"
+
+#define STORAGE_MEMINC 16
+
+#ifndef TXT_SQL_CONVERT
+// reset by inter_config_read()
+struct storage *storage_pt=NULL;
+struct guild_storage *guild_storage_pt=NULL;
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+#endif //TXT_SQL_CONVERT
+// storage data -> DB conversion
+int storage_tosql(int account_id,struct storage *p){
+ int i,j;
+// int eqcount=1;
+// int noteqcount=1;
+ int count=0;
+ struct itemtmp mapitem[MAX_STORAGE];
+ for(i=0;i<MAX_STORAGE;i++){
+ if(p->storage_[i].nameid>0){
+ mapitem[count].flag=0;
+ mapitem[count].id = p->storage_[i].id;
+ mapitem[count].nameid=p->storage_[i].nameid;
+ mapitem[count].amount = p->storage_[i].amount;
+ mapitem[count].equip = p->storage_[i].equip;
+ mapitem[count].identify = p->storage_[i].identify;
+ mapitem[count].refine = p->storage_[i].refine;
+ mapitem[count].attribute = p->storage_[i].attribute;
+ for(j=0; j<MAX_SLOTS; j++)
+ mapitem[count].card[j] = p->storage_[i].card[j];
+ count++;
+ }
+ }
+
+ memitemdata_to_sql(mapitem, count, account_id,TABLE_STORAGE);
+
+ //printf ("storage dump to DB - id: %d (total: %d)\n", account_id, j);
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+
+// DB -> storage data conversion
+int storage_fromsql(int account_id, struct storage *p){
+ int i=0,j;
+ char * str_p = tmp_sql;
+
+ memset(p,0,sizeof(struct storage)); //clean up memory
+ p->storage_amount = 0;
+ p->account_id = account_id;
+
+ // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
+ str_p += sprintf(str_p,"SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`");
+
+ for (j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`", j);
+
+ str_p += sprintf(str_p," FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id);
+
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+
+ if (sql_res) {
+ while((sql_row = mysql_fetch_row(sql_res)) && i<MAX_STORAGE) { //start to fetch
+ p->storage_[i].id= atoi(sql_row[0]);
+ p->storage_[i].nameid= atoi(sql_row[1]);
+ p->storage_[i].amount= atoi(sql_row[2]);
+ p->storage_[i].equip= atoi(sql_row[3]);
+ p->storage_[i].identify= atoi(sql_row[4]);
+ p->storage_[i].refine= atoi(sql_row[5]);
+ p->storage_[i].attribute= atoi(sql_row[6]);
+ for (j=0; j<MAX_SLOTS; j++)
+ p->storage_[i].card[j]= atoi(sql_row[7+j]);
+ i++;
+ }
+ p->storage_amount = i;
+ mysql_free_result(sql_res);
+ }
+
+ ShowInfo ("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount);
+ return 1;
+}
+#endif //TXT_SQL_CONVERT
+// Save guild_storage data to sql
+int guild_storage_tosql(int guild_id, struct guild_storage *p){
+ int i,j;
+// int eqcount=1;
+// int noteqcount=1;
+ int count=0;
+ struct itemtmp mapitem[MAX_GUILD_STORAGE];
+ for(i=0;i<MAX_GUILD_STORAGE;i++){
+ if(p->storage_[i].nameid>0){
+ mapitem[count].flag=0;
+ mapitem[count].id = p->storage_[i].id;
+ mapitem[count].nameid=p->storage_[i].nameid;
+ mapitem[count].amount = p->storage_[i].amount;
+ mapitem[count].equip = p->storage_[i].equip;
+ mapitem[count].identify = p->storage_[i].identify;
+ mapitem[count].refine = p->storage_[i].refine;
+ mapitem[count].attribute = p->storage_[i].attribute;
+ for (j=0; j<MAX_SLOTS; j++)
+ mapitem[count].card[j] = p->storage_[i].card[j];
+ count++;
+ }
+ }
+
+ memitemdata_to_sql(mapitem, count, guild_id,TABLE_GUILD_STORAGE);
+
+ ShowInfo ("guild storage save to DB - id: %d (total: %d)\n", guild_id,i);
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+// Load guild_storage data to mem
+int guild_storage_fromsql(int guild_id, struct guild_storage *p){
+ int i=0,j;
+ struct guild_storage *gs=guild_storage_pt;
+ char * str_p = tmp_sql;
+ p=gs;
+
+ memset(p,0,sizeof(struct guild_storage)); //clean up memory
+ p->storage_amount = 0;
+ p->guild_id = guild_id;
+
+ // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
+ str_p += sprintf(str_p,"SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`");
+
+ for (j=0; j<MAX_SLOTS; j++)
+ str_p += sprintf(str_p, ", `card%d`", j);
+
+ str_p += sprintf(str_p," FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id);
+
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+
+ if (sql_res) {
+ while((sql_row = mysql_fetch_row(sql_res)) && i < MAX_GUILD_STORAGE) { //start to fetch
+ p->storage_[i].id= atoi(sql_row[0]);
+ p->storage_[i].nameid= atoi(sql_row[1]);
+ p->storage_[i].amount= atoi(sql_row[2]);
+ p->storage_[i].equip= atoi(sql_row[3]);
+ p->storage_[i].identify= atoi(sql_row[4]);
+ p->storage_[i].refine= atoi(sql_row[5]);
+ p->storage_[i].attribute= atoi(sql_row[6]);
+ for (j=0; j<MAX_SLOTS; j++)
+ p->storage_[i].card[j] = atoi(sql_row[7+j]);
+ i++;
+ }
+ p->storage_amount = i;
+ mysql_free_result(sql_res);
+ }
+ ShowInfo ("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount);
+ return 0;
+}
+
+//---------------------------------------------------------
+// storage data initialize
+int inter_storage_sql_init(void){
+
+ //memory alloc
+ ShowDebug("interserver storage memory initialize....(%d byte)\n",sizeof(struct storage));
+ storage_pt = (struct storage*)aCalloc(sizeof(struct storage), 1);
+ guild_storage_pt = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1);
+// memset(storage_pt,0,sizeof(struct storage)); //Calloc sets stuff to 0 already. [Skotlex]
+// memset(guild_storage_pt,0,sizeof(struct guild_storage));
+
+ return 1;
+}
+// storage data finalize
+void inter_storage_sql_final(void)
+{
+ if (storage_pt) aFree(storage_pt);
+ if (guild_storage_pt) aFree(guild_storage_pt);
+ return;
+}
+// q?f[^?
+int inter_storage_delete(int account_id)
+{
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `account_id`='%d'",storage_db, account_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return 0;
+}
+int inter_guild_storage_delete(int guild_id)
+{
+ sprintf(tmp_sql, "DELETE FROM `%s` WHERE `guild_id`='%d'",guild_storage_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ return 0;
+}
+
+//---------------------------------------------------------
+// packet from map server
+
+// recive packet about storage data
+int mapif_load_storage(int fd,int account_id){
+ //load from DB
+ WFIFOHEAD(fd, sizeof(struct storage)+8);
+ storage_fromsql(account_id, storage_pt);
+ WFIFOW(fd,0)=0x3810;
+ WFIFOW(fd,2)=sizeof(struct storage)+8;
+ WFIFOL(fd,4)=account_id;
+ memcpy(WFIFOP(fd,8),storage_pt,sizeof(struct storage));
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+// send ack to map server which is "storage data save ok."
+int mapif_save_storage_ack(int fd,int account_id){
+ WFIFOHEAD(fd, 7);
+ WFIFOW(fd,0)=0x3811;
+ WFIFOL(fd,2)=account_id;
+ WFIFOB(fd,6)=0;
+ WFIFOSET(fd,7);
+ return 0;
+}
+
+int mapif_load_guild_storage(int fd,int account_id,int guild_id)
+{
+ int guild_exist=1;
+ WFIFOHEAD(fd, sizeof(struct guild_storage)+12);
+ WFIFOW(fd,0)=0x3818;
+
+#if 0 // innodb guilds should render this check unnecessary [Aru]
+ // Check if guild exists, I may write a function for this later, coz I use it several times.
+ //printf("- Check if guild %d exists\n",g->guild_id);
+ sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+ guild_exist = atoi (sql_row[0]);
+ //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes"));
+ }
+ mysql_free_result(sql_res) ; //resource free
+#endif
+ if(guild_exist==1) {
+ guild_storage_fromsql(guild_id,guild_storage_pt);
+ WFIFOW(fd,2)=sizeof(struct guild_storage)+12;
+ WFIFOL(fd,4)=account_id;
+ WFIFOL(fd,8)=guild_id;
+ memcpy(WFIFOP(fd,12),guild_storage_pt,sizeof(struct guild_storage));
+ }
+ else {
+ WFIFOW(fd,2)=12;
+ WFIFOL(fd,4)=account_id;
+ WFIFOL(fd,8)=0;
+ }
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail)
+{
+ WFIFOHEAD(fd,11);
+ WFIFOW(fd,0)=0x3819;
+ WFIFOL(fd,2)=account_id;
+ WFIFOL(fd,6)=guild_id;
+ WFIFOB(fd,10)=fail;
+ WFIFOSET(fd,11);
+ return 0;
+}
+
+//---------------------------------------------------------
+// packet from map server
+
+// recive request about storage data
+int mapif_parse_LoadStorage(int fd){
+ RFIFOHEAD(fd);
+ mapif_load_storage(fd,RFIFOL(fd,2));
+ return 0;
+}
+// storage data recive and save
+int mapif_parse_SaveStorage(int fd){
+ int account_id;
+ int len;
+ RFIFOHEAD(fd);
+ account_id=RFIFOL(fd,4);
+ len=RFIFOW(fd,2);
+ if(sizeof(struct storage)!=len-8){
+ ShowError("inter storage: data size error %d %d\n",sizeof(struct storage),len-8);
+ }else{
+ memcpy(&storage_pt[0],RFIFOP(fd,8),sizeof(struct storage));
+ storage_tosql(account_id, storage_pt);
+ mapif_save_storage_ack(fd,account_id);
+ }
+ return 0;
+}
+
+int mapif_parse_LoadGuildStorage(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6));
+ return 0;
+}
+
+int mapif_parse_SaveGuildStorage(int fd)
+{
+ int guild_exist=1;
+ int guild_id;
+ int len;
+ RFIFOHEAD(fd);
+ guild_id=RFIFOL(fd,8);
+ len=RFIFOW(fd,2);
+ if(sizeof(struct guild_storage)!=len-12){
+ ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12);
+ }
+ else {
+#if 0 // Again, innodb key checks make the check pointless
+ // Check if guild exists, I may write a function for this later, coz I use it several times.
+ //printf("- Check if guild %d exists\n",g->guild_id);
+ sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+ guild_exist = atoi (sql_row[0]);
+ //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes"));
+ }
+ mysql_free_result(sql_res) ; //resource free
+#endif
+ if(guild_exist==1) {
+ memcpy(guild_storage_pt,RFIFOP(fd,12),sizeof(struct guild_storage));
+ guild_storage_tosql(guild_id,guild_storage_pt);
+ mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0);
+ }
+ else
+ mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1);
+ }
+ return 0;
+}
+
+
+int inter_storage_parse_frommap(int fd){
+ RFIFOHEAD(fd);
+ switch(RFIFOW(fd,0)){
+ case 0x3010: mapif_parse_LoadStorage(fd); break;
+ case 0x3011: mapif_parse_SaveStorage(fd); break;
+ case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
+ case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/int_storage.h b/src/char_sql/int_storage.h
index c886a45e2..3cba41e64 100644
--- a/src/char_sql/int_storage.h
+++ b/src/char_sql/int_storage.h
@@ -1,17 +1,17 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _INT_STORAGE_SQL_H_
-#define _INT_STORAGE_SQL_H_
-
-int inter_storage_sql_init(void);
-void inter_storage_sql_final(void);
-int inter_storage_delete(int account_id);
-int inter_guild_storage_delete(int guild_id);
-
-int inter_storage_parse_frommap(int fd);
-
-//Exported for use in the TXT-SQL converter.
-int storage_tosql(int account_id,struct storage *p);
-int guild_storage_tosql(int guild_id, struct guild_storage *p);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_STORAGE_SQL_H_
+#define _INT_STORAGE_SQL_H_
+
+int inter_storage_sql_init(void);
+void inter_storage_sql_final(void);
+int inter_storage_delete(int account_id);
+int inter_guild_storage_delete(int guild_id);
+
+int inter_storage_parse_frommap(int fd);
+
+//Exported for use in the TXT-SQL converter.
+int storage_tosql(int account_id,struct storage *p);
+int guild_storage_tosql(int guild_id, struct guild_storage *p);
+#endif
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c
index 5ce452717..64983cfc6 100644
--- a/src/char_sql/inter.c
+++ b/src/char_sql/inter.c
@@ -1,822 +1,822 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-// original code from athena
-// SQL conversion by Jioh L. Jung
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "char.h"
-#include "../common/strlib.h"
-#include "../common/showmsg.h"
-#include "inter.h"
-#include "int_party.h"
-#include "int_guild.h"
-#include "int_storage.h"
-#include "int_pet.h"
-#include "int_homun.h" //albator
-
-#define WISDATA_TTL (60*1000) // Wisƒf[ƒ^‚̐Ά‘ΆŽžŠΤ(60•b)
-#define WISDELLIST_MAX 256 // Wisƒf[ƒ^νœƒŠƒXƒg‚Μ—v‘f”
-
-
-MYSQL mysql_handle;
-MYSQL_RES* sql_res ;
-MYSQL_ROW sql_row ;
-int sql_fields, sql_cnt;
-char tmp_sql[65535];
-
-MYSQL lmysql_handle;
-MYSQL_RES* lsql_res ;
-MYSQL_ROW lsql_row ;
-
-int char_server_port = 3306;
-char char_server_ip[32] = "127.0.0.1";
-char char_server_id[32] = "ragnarok";
-char char_server_pw[32] = "ragnarok";
-char char_server_db[32] = "ragnarok";
-char default_codepage[32] = ""; //Feature by irmin.
-
-int login_server_port = 3306;
-char login_server_ip[32] = "127.0.0.1";
-char login_server_id[32] = "ragnarok";
-char login_server_pw[32] = "ragnarok";
-char login_server_db[32] = "ragnarok";
-
-#ifndef TXT_SQL_CONVERT
-
-static struct accreg *accreg_pt;
-unsigned int party_share_level = 10;
-char main_chat_nick[16] = "Main";
-
-// sending packet list
-// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex]
-int inter_send_packet_length[]={
- -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0,
- 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0,
- 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1,
- 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-// recv. packet list
-int inter_recv_packet_length[]={
- -1,-1, 7,-1, -1,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f
- 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f
- -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f
- -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f
- 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 48,14,-1, 6, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f
- -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3090 - 0x309f Homunculus packets [albator]
-};
-
-struct WisData {
- int id, fd, count,len;
- unsigned long tick;
- unsigned char src[24], dst[24], msg[512];
-};
-static struct dbt * wis_db = NULL;
-static int wis_dellist[WISDELLIST_MAX], wis_delnum;
-
-int inter_sql_test (void);
-
-#endif //TXT_SQL_CONVERT
-//--------------------------------------------------------
-// Save registry to sql
-int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type){
-
- int j;
- char temp_str[64]; //Needs be twice the source to ensure it fits [Skotlex]
- char temp_str2[512];
- if (account_id<=0) return 0;
- reg->account_id=account_id;
- reg->char_id = char_id;
-
- switch (type) {
- case 3: //Char Reg
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id);
- break;
- case 2: //Account Reg
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'",reg_db, account_id);
- break;
- case 1: //Account2 Reg
- ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- default:
- ShowError("inter_accreg_tosql: Invalid type %d\n", type);
- return 0;
-
- }
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- if (reg->reg_num<=0) return 0;
-
- for(j=0;j<reg->reg_num;j++){
- if(reg->reg[j].str != NULL){
- sprintf(tmp_sql,"INSERT INTO `%s` (`type`, `account_id`, `char_id`, `str`, `value`) VALUES ('%d','%d','%d','%s','%s')",
- reg_db, type, type!=3?reg->account_id:0, type==3?reg->char_id:0,
- jstrescapecpy(temp_str,reg->reg[j].str), jstrescapecpy(temp_str2,reg->reg[j].value));
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
- }
- return 1;
-}
-#ifndef TXT_SQL_CONVERT
-
-// Load account_reg from sql (type=2)
-int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type)
-{
- int j=0;
- if (reg==NULL) return 0;
- memset(reg, 0, sizeof(struct accreg));
- reg->account_id=account_id;
- reg->char_id=char_id;
-
- //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
- switch (type) {
- case 3: //char reg
- sprintf (tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, reg->char_id);
- break;
- case 2: //account reg
- sprintf (tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'",reg_db, reg->account_id);
- break;
- case 1: //account2 reg
- ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
- return 0;
- }
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
-
- if (sql_res) {
- for(j=0;(sql_row = mysql_fetch_row(sql_res));j++){
- strcpy(reg->reg[j].str, sql_row[0]);
- strcpy(reg->reg[j].value, sql_row[1]);
- }
- mysql_free_result(sql_res);
- }
- reg->reg_num=j;
- return 1;
-}
-
-// Initialize
-int inter_accreg_sql_init(void)
-{
- CREATE(accreg_pt, struct accreg, 1);
- return 0;
-
-}
-#endif //TXT_SQL_CONVERT
-
-/*==========================================
- * read config file
- *------------------------------------------
- */
-static int inter_config_read(const char *cfgName) {
- int i;
- char line[1024], w1[1024], w2[1024];
- FILE *fp;
-
- fp=fopen(cfgName,"r");
- if(fp==NULL){
- ShowError("file not found: %s\n", cfgName);
- return 1;
- }
-
- ShowInfo("reading file %s...\n",cfgName);
-
- while(fgets(line, 1020, fp)){
- i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
- if(i!=2)
- continue;
-
- if(strcmpi(w1,"char_server_ip")==0){
- strcpy(char_server_ip, w2);
- ShowStatus ("set char_server_ip : %s\n",w2);
- }
- else if(strcmpi(w1,"char_server_port")==0){
- char_server_port=atoi(w2);
- ShowStatus ("set char_server_port : %s\n",w2);
- }
- else if(strcmpi(w1,"char_server_id")==0){
- strcpy(char_server_id, w2);
- ShowStatus ("set char_server_id : %s\n",w2);
- }
- else if(strcmpi(w1,"char_server_pw")==0){
- strcpy(char_server_pw, w2);
- ShowStatus ("set char_server_pw : %s\n",w2);
- }
- else if(strcmpi(w1,"char_server_db")==0){
- strcpy(char_server_db, w2);
- ShowStatus ("set char_server_db : %s\n",w2);
- }
- else if(strcmpi(w1,"default_codepage")==0){
- strcpy(default_codepage, w2);
- ShowStatus ("set default_codepage : %s\n",w2);
- }
- //Logins information to be read from the inter_athena.conf
- //for character deletion (checks email in the loginDB)
- else if(strcmpi(w1,"login_server_ip")==0){
- strcpy(login_server_ip, w2);
- ShowStatus ("set login_server_ip : %s\n",w2);
- }
- else if(strcmpi(w1,"login_server_port")==0){
- login_server_port=atoi(w2);
- ShowStatus ("set login_server_port : %s\n",w2);
- }
- else if(strcmpi(w1,"login_server_id")==0){
- strcpy(login_server_id, w2);
- ShowStatus ("set login_server_id : %s\n",w2);
- }
- else if(strcmpi(w1,"login_server_pw")==0){
- strcpy(login_server_pw, w2);
- ShowStatus ("set login_server_pw : %s\n",w2);
- }
- else if(strcmpi(w1,"login_server_db")==0){
- strcpy(login_server_db, w2);
- ShowStatus ("set login_server_db : %s\n",w2);
- }
-#ifndef TXT_SQL_CONVERT
- else if(strcmpi(w1,"party_share_level")==0){
- party_share_level=(unsigned int)atof(w2);
- }
- else if(strcmpi(w1,"log_inter")==0){
- log_inter = atoi(w2);
- }
- else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza]
- strcpy(main_chat_nick, w2); //
- }
-#endif //TXT_SQL_CONVERT
- else if(strcmpi(w1,"import")==0){
- inter_config_read(w2);
- }
- }
- fclose(fp);
-
- ShowInfo ("done reading %s.\n", cfgName);
-
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-
-// Save interlog into sql
-int inter_log(char *fmt,...)
-{
- char str[255];
- char temp_str[510]; //Needs be twice as long as str[] //Skotlex
- va_list ap;
- va_start(ap,fmt);
-
- vsprintf(str,fmt,ap);
- sprintf(tmp_sql,"INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')",interlog_db, jstrescapecpy(temp_str,str));
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- va_end(ap);
- return 0;
-}
-
-/*======================================================
- * Does a mysql_ping to all connection handles. [Skotlex]
- *------------------------------------------------------
- */
-int inter_sql_ping(int tid, unsigned int tick, int id, int data)
-{
- ShowInfo("Pinging SQL server to keep connection alive...\n");
- mysql_ping(&mysql_handle);
- if(char_gm_read)
- mysql_ping(&lmysql_handle);
- return 0;
-}
-#endif //TXT_SQL_CONVERT
-
-// initialize
-int inter_init_sql(const char *file)
-{
- //int i;
-
- ShowInfo ("interserver initialize...\n");
- inter_config_read(file);
-
- //DB connection initialized
- mysql_init(&mysql_handle);
- ShowInfo("Connect Character DB server.... (Character Server)\n");
- if(!mysql_real_connect(&mysql_handle, char_server_ip, char_server_id, char_server_pw,
- char_server_db ,char_server_port, (char *)NULL, 0)) {
- //pointer check
- ShowFatalError("%s\n",mysql_error(&mysql_handle));
- exit(1);
- }
-#ifndef TXT_SQL_CONVERT
- else if (inter_sql_test()) {
- ShowStatus("Connect Success! (Character Server)\n");
- }
-
- if(char_gm_read) {
- mysql_init(&lmysql_handle);
- ShowInfo("Connect Character DB server.... (login server)\n");
- if(!mysql_real_connect(&lmysql_handle, login_server_ip, login_server_id, login_server_pw,
- login_server_db ,login_server_port, (char *)NULL, 0)) {
- //pointer check
- ShowFatalError("%s\n",mysql_error(&lmysql_handle));
- exit(1);
- }else {
- ShowStatus ("Connect Success! (Login Server)\n");
- }
- }
-#endif //TXT_SQL_CONVERT
- if(strlen(default_codepage) > 0 ) {
- sprintf( tmp_sql, "SET NAMES %s", default_codepage );
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-#ifndef TXT_SQL_CONVERT
- if(char_gm_read)
- if (mysql_query(&lmysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&lmysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-#endif //TXT_SQL_CONVERT
- }
-
-#ifndef TXT_SQL_CONVERT
- wis_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
- inter_guild_sql_init();
- inter_storage_sql_init();
- inter_party_sql_init();
- inter_pet_sql_init();
- inter_homunculus_sql_init(); // albator
- inter_accreg_sql_init();
-
- if (connection_ping_interval) {
- add_timer_func_list(inter_sql_ping, "inter_sql_ping");
- add_timer_interval(gettick()+connection_ping_interval*60*60*1000,
- inter_sql_ping, 0, 0, connection_ping_interval*60*60*1000);
- }
-#endif //TXT_SQL_CONVERT
- return 0;
-}
-#ifndef TXT_SQL_CONVERT
-
-int inter_sql_test (void)
-{
- const char fields[][24] = {
- "father", // version 1363
- "fame", // version 1491
- };
- char buf[1024] = "";
- int i;
-
- sprintf(tmp_sql, "EXPLAIN `%s`",char_db);
- if (mysql_query(&mysql_handle, tmp_sql)) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
- // store DB fields
- if (sql_res) {
- while((sql_row = mysql_fetch_row(sql_res))) {
- strcat (buf, sql_row[0]);
- strcat (buf, " ");
- }
- }
-
- // check DB strings
- for (i = 0; i < (int)(sizeof(fields) / sizeof(fields[0])); i++) {
- if(!strstr(buf, fields[i])) {
- ShowSQL ("Field `%s` not be found in `%s`. Consider updating your database!\n", fields[i], char_db);
- exit(1);
- }
- }
-
- mysql_free_result(sql_res);
-
- return 1;
-}
-
-// finalize
-void inter_final(void) {
- wis_db->destroy(wis_db, NULL);
-
- inter_guild_sql_final();
- inter_storage_sql_final();
- inter_party_sql_final();
- inter_pet_sql_final();
- inter_homunculus_sql_final(); //[orn]
-
- if (accreg_pt) aFree(accreg_pt);
- return;
-}
-
-int inter_mapif_init(int fd) {
- inter_guild_mapif_init(fd);
-
- return 0;
-}
-
-
-//--------------------------------------------------------
-
-// GM message sending
-int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) {
- unsigned char buf[2048];
-
- if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex]
- WBUFW(buf, 0) = 0x3800;
- WBUFW(buf, 2) = len;
- WBUFL(buf, 4) = color;
- memcpy(WBUFP(buf, 8), mes, len-8);
- mapif_sendallwos(sfd, buf, len);
- return 0;
-}
-
-// Wis sending
-int mapif_wis_message(struct WisData *wd) {
- unsigned char buf[2048];
- if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex]
-
- WBUFW(buf, 0) = 0x3801;
- WBUFW(buf, 2) = 56 +wd->len;
- WBUFL(buf, 4) = wd->id;
- memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH);
- memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH);
- memcpy(WBUFP(buf,56), wd->msg, wd->len);
- wd->count = mapif_sendall(buf,WBUFW(buf,2));
-
- return 0;
-}
-// Wis sending result
-int mapif_wis_end(struct WisData *wd,int flag)
-{
- unsigned char buf[27];
-
- WBUFW(buf, 0)=0x3802;
- memcpy(WBUFP(buf, 2),wd->src,24);
- WBUFB(buf,26)=flag;
- mapif_send(wd->fd,buf,27);
-// printf("inter server wis_end %d\n",flag);
- return 0;
-}
-
-int mapif_account_reg(int fd,unsigned char *src)
-{
-// unsigned char buf[WBUFW(src,2)]; <- Hey, can this really be done? [Skotlex]
- unsigned char *buf = aCalloc(1,WBUFW(src,2)); // [Lance] - Skot... Dynamic allocation is better :D
- memcpy(WBUFP(buf,0),src,WBUFW(src,2));
- WBUFW(buf, 0)=0x3804;
- mapif_sendallwos(fd, buf, WBUFW(buf,2));
- aFree(buf);
- return 0;
-}
-
-// Send the requested account_reg
-int mapif_account_reg_reply(int fd,int account_id,int char_id, int type)
-{
- struct accreg *reg=accreg_pt;
- WFIFOHEAD(fd, 13 + 5000);
- inter_accreg_fromsql(account_id,char_id,reg,type);
-
- WFIFOW(fd,0)=0x3804;
- WFIFOL(fd,4)=account_id;
- WFIFOL(fd,8)=char_id;
- WFIFOB(fd,12)=type;
- if(reg->reg_num==0){
- WFIFOW(fd,2)=13;
- }else{
- int i,p;
- for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) {
- p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place.
- p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].value)+1;
- }
- WFIFOW(fd,2)=p;
- if (p>= 5000)
- ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id);
- }
- WFIFOSET(fd,WFIFOW(fd,2));
- return 0;
-}
-
-int mapif_send_gmaccounts()
-{
- int i, len = 4;
- unsigned char buf[32000];
-
- // forward the gm accounts to the map server
- len = 4;
- WBUFW(buf,0) = 0x2b15;
-
- for(i = 0; i < GM_num; i++) {
- WBUFL(buf, len) = gm_account[i].account_id;
- WBUFB(buf, len+4) = (unsigned char)gm_account[i].level;
- len += 5;
- }
- WBUFW(buf, 2) = len;
- mapif_sendall(buf, len);
-
- return 0;
-}
-
-//Sends to map server the current max Account/Char id [Skotlex]
-void mapif_send_maxid(int account_id, int char_id)
-{
- unsigned char buf[12];
-
- WBUFW(buf,0) = 0x2b07;
- WBUFL(buf,2) = account_id;
- WBUFL(buf,6) = char_id;
- mapif_sendall(buf, 10);
-}
-
-//Request to kick char from a certain map server. [Skotlex]
-int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason)
-{
- if (fd >= 0)
- {
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x2b1f;
- WFIFOL(fd,2) = account_id;
- WFIFOB(fd,6) = reason;
- WFIFOSET(fd,7);
- return 0;
- }
- return -1;
-}
-
-//--------------------------------------------------------
-
-// Existence check of WISP data
-int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) {
- unsigned long tick;
- struct WisData *wd = (struct WisData *)data;
- tick = va_arg(ap, unsigned long);
-
- if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX)
- wis_dellist[wis_delnum++] = wd->id;
-
- return 0;
-}
-
-int check_ttl_wisdata(void) {
- unsigned long tick = gettick();
- int i;
-
- do {
- wis_delnum = 0;
- wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick);
- for(i = 0; i < wis_delnum; i++) {
- struct WisData *wd = idb_get(wis_db, wis_dellist[i]);
- ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst);
- // removed. not send information after a timeout. Just no answer for the player
- //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- idb_remove(wis_db, wd->id);
- }
- } while(wis_delnum >= WISDELLIST_MAX);
-
- return 0;
-}
-
-//--------------------------------------------------------
-
-// GM message sending
-int mapif_parse_GMmessage(int fd)
-{
- RFIFOHEAD(fd);
- mapif_GMmessage(RFIFOP(fd, 8), RFIFOW(fd, 2), RFIFOL(fd, 4), fd);
- return 0;
-}
-
-
-// Wisp/page request to send
-int mapif_parse_WisRequest(int fd) {
- struct WisData* wd;
- static int wisid = 0;
- char name[NAME_LENGTH], t_name[NAME_LENGTH*2]; //Needs space to allocate names with escaped chars [Skotlex]
- RFIFOHEAD(fd);
- if ( fd <= 0 ) {return 0;} // check if we have a valid fd
-
- if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) {
- ShowWarning("inter: Wis message size too long.\n");
- return 0;
- } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows...
- ShowError("inter: Wis message doesn't exist.\n");
- return 0;
- }
- memcpy(name, RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex]
- name[NAME_LENGTH-1]= '\0';
-
- sprintf (tmp_sql, "SELECT `name` FROM `%s` WHERE `name`='%s'",
- char_db, jstrescapecpy(t_name, name));
- if(mysql_query(&mysql_handle, tmp_sql) ) {
- ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- sql_res = mysql_store_result(&mysql_handle);
-
- // search if character exists before to ask all map-servers
- if (!(sql_row = mysql_fetch_row(sql_res))) {
- unsigned char buf[27];
- WBUFW(buf, 0) = 0x3802;
- memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH);
- WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- mapif_send(fd, buf, 27);
- // Character exists. So, ask all map-servers
- } else {
- // to be sure of the correct name, rewrite it
- memset(name, 0, NAME_LENGTH);
- strncpy(name, sql_row[0], NAME_LENGTH);
- // if source is destination, don't ask other servers.
- if (strcmp((char*)RFIFOP(fd,4),name) == 0) {
- unsigned char buf[27];
- WBUFW(buf, 0) = 0x3802;
- memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH);
- WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- mapif_send(fd, buf, 27);
- } else {
-
- CREATE(wd, struct WisData, 1);
-
- // Whether the failure of previous wisp/page transmission (timeout)
- check_ttl_wisdata();
-
- wd->id = ++wisid;
- wd->fd = fd;
- wd->len= RFIFOW(fd,2)-52;
- memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH);
- memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH);
- memcpy(wd->msg, RFIFOP(fd,52), wd->len);
- wd->tick = gettick();
- idb_put(wis_db, wd->id, wd);
- mapif_wis_message(wd);
- }
- }
-
- //Freeing ... O.o
- if(sql_res){
- mysql_free_result(sql_res);
- }
-
- return 0;
-}
-
-
-// Wisp/page transmission result
-int mapif_parse_WisReply(int fd) {
- int id, flag;
- struct WisData *wd;
- RFIFOHEAD(fd);
- id = RFIFOL(fd,2);
- flag = RFIFOB(fd,6);
- wd = idb_get(wis_db, id);
- if (wd == NULL)
- return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server
-
- if ((--wd->count) <= 0 || flag != 1) {
- mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
- idb_remove(wis_db, id);
- }
-
- return 0;
-}
-
-// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers)
-int mapif_parse_WisToGM(int fd) {
- unsigned char buf[2048]; // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
- RFIFOHEAD(fd);
- ShowDebug("Sent packet back!\n");
- memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2));
- WBUFW(buf, 0) = 0x3803;
- mapif_sendall(buf, RFIFOW(fd,2));
-
- return 0;
-}
-
-// Save account_reg into sql (type=2)
-int mapif_parse_Registry(int fd)
-{
- int j,p,len, max;
- struct accreg *reg=accreg_pt;
- RFIFOHEAD(fd);
- memset(accreg_pt,0,sizeof(struct accreg));
- switch (RFIFOB(fd, 12)) {
- case 3: //Character registry
- max = GLOBAL_REG_NUM;
- break;
- case 2: //Account Registry
- max = ACCOUNT_REG_NUM;
- break;
- case 1: //Account2 registry, must be sent over to login server.
- return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4);
- default:
- return 1;
- }
- for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){
- sscanf(RFIFOP(fd,p), "%31c%n",reg->reg[j].str,&len);
- reg->reg[j].str[len]='\0';
- p +=len+1; //+1 to skip the '\0' between strings.
- sscanf(RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len);
- reg->reg[j].value[len]='\0';
- p +=len+1;
- }
- reg->reg_num=j;
-
- inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12));
- mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers.
- return 0;
-}
-
-// Request the value of all registries.
-int mapif_parse_RegistryRequest(int fd)
-{
- RFIFOHEAD(fd);
- //Load Char Registry
- if (RFIFOB(fd,12))
- mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3);
- //Load Account Registry
- if (RFIFOB(fd,11))
- mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2);
- //Ask Login Server for Account2 values.
- if (RFIFOB(fd,10))
- request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2);
- return 1;
-}
-
-//--------------------------------------------------------
-int inter_parse_frommap(int fd)
-{
- int cmd;
- int len=0;
- RFIFOHEAD(fd);
- cmd=RFIFOW(fd,0);
- // interŽIŠΗŠ‚©‚𒲂ׂ
- if(cmd < 0x3000 || cmd >= 0x3000 + (sizeof(inter_recv_packet_length)/
- sizeof(inter_recv_packet_length[0]) ) )
- return 0;
-
- if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex]
- return 0;
-
- // ƒpƒPƒbƒg’·‚𒲂ׂι
- if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0)
- return 2;
-
- switch(cmd){
- case 0x3000: mapif_parse_GMmessage(fd); break;
- case 0x3001: mapif_parse_WisRequest(fd); break;
- case 0x3002: mapif_parse_WisReply(fd); break;
- case 0x3003: mapif_parse_WisToGM(fd); break;
- case 0x3004: mapif_parse_Registry(fd); break;
- case 0x3005: mapif_parse_RegistryRequest(fd); break;
- default:
- if(inter_party_parse_frommap(fd))
- break;
- if(inter_guild_parse_frommap(fd))
- break;
- if(inter_storage_parse_frommap(fd))
- break;
- if(inter_pet_parse_frommap(fd))
- break;
- if(inter_homunculus_parse_frommap(fd)) //albator
- break;
- return 0;
- }
-
- RFIFOSKIP(fd, len);
- return 1;
-}
-
-// RFIFO check
-int inter_check_length(int fd, int length)
-{
- RFIFOHEAD(fd);
- if(length==-1){ // v-len packet
- if(RFIFOREST(fd)<4) // packet not yet
- return 0;
- length = RFIFOW(fd, 2);
- }
-
- if((int)RFIFOREST(fd) < length) // packet not yet
- return 0;
-
- return length;
-}
-#endif //TXT_SQL_CONVERT
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+// original code from athena
+// SQL conversion by Jioh L. Jung
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "char.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+#include "inter.h"
+#include "int_party.h"
+#include "int_guild.h"
+#include "int_storage.h"
+#include "int_pet.h"
+#include "int_homun.h" //albator
+
+#define WISDATA_TTL (60*1000) // Wisƒf[ƒ^‚̐Ά‘ΆŽžŠΤ(60•b)
+#define WISDELLIST_MAX 256 // Wisƒf[ƒ^νœƒŠƒXƒg‚Μ—v‘f”
+
+
+MYSQL mysql_handle;
+MYSQL_RES* sql_res ;
+MYSQL_ROW sql_row ;
+int sql_fields, sql_cnt;
+char tmp_sql[65535];
+
+MYSQL lmysql_handle;
+MYSQL_RES* lsql_res ;
+MYSQL_ROW lsql_row ;
+
+int char_server_port = 3306;
+char char_server_ip[32] = "127.0.0.1";
+char char_server_id[32] = "ragnarok";
+char char_server_pw[32] = "ragnarok";
+char char_server_db[32] = "ragnarok";
+char default_codepage[32] = ""; //Feature by irmin.
+
+int login_server_port = 3306;
+char login_server_ip[32] = "127.0.0.1";
+char login_server_id[32] = "ragnarok";
+char login_server_pw[32] = "ragnarok";
+char login_server_db[32] = "ragnarok";
+
+#ifndef TXT_SQL_CONVERT
+
+static struct accreg *accreg_pt;
+unsigned int party_share_level = 10;
+char main_chat_nick[16] = "Main";
+
+// sending packet list
+// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex]
+int inter_send_packet_length[]={
+ -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0,
+ 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1,
+ 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+// recv. packet list
+int inter_recv_packet_length[]={
+ -1,-1, 7,-1, -1,13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f
+ 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f
+ -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f
+ -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f
+ 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 48,14,-1, 6, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f
+ -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3090 - 0x309f Homunculus packets [albator]
+};
+
+struct WisData {
+ int id, fd, count,len;
+ unsigned long tick;
+ unsigned char src[24], dst[24], msg[512];
+};
+static struct dbt * wis_db = NULL;
+static int wis_dellist[WISDELLIST_MAX], wis_delnum;
+
+int inter_sql_test (void);
+
+#endif //TXT_SQL_CONVERT
+//--------------------------------------------------------
+// Save registry to sql
+int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type){
+
+ int j;
+ char temp_str[64]; //Needs be twice the source to ensure it fits [Skotlex]
+ char temp_str2[512];
+ if (account_id<=0) return 0;
+ reg->account_id=account_id;
+ reg->char_id = char_id;
+
+ switch (type) {
+ case 3: //Char Reg
+ //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, char_id);
+ break;
+ case 2: //Account Reg
+ //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
+ sprintf(tmp_sql,"DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'",reg_db, account_id);
+ break;
+ case 1: //Account2 Reg
+ ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
+ default:
+ ShowError("inter_accreg_tosql: Invalid type %d\n", type);
+ return 0;
+
+ }
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ if (reg->reg_num<=0) return 0;
+
+ for(j=0;j<reg->reg_num;j++){
+ if(reg->reg[j].str != NULL){
+ sprintf(tmp_sql,"INSERT INTO `%s` (`type`, `account_id`, `char_id`, `str`, `value`) VALUES ('%d','%d','%d','%s','%s')",
+ reg_db, type, type!=3?reg->account_id:0, type==3?reg->char_id:0,
+ jstrescapecpy(temp_str,reg->reg[j].str), jstrescapecpy(temp_str2,reg->reg[j].value));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+ }
+ return 1;
+}
+#ifndef TXT_SQL_CONVERT
+
+// Load account_reg from sql (type=2)
+int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type)
+{
+ int j=0;
+ if (reg==NULL) return 0;
+ memset(reg, 0, sizeof(struct accreg));
+ reg->account_id=account_id;
+ reg->char_id=char_id;
+
+ //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`)
+ switch (type) {
+ case 3: //char reg
+ sprintf (tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'",reg_db, reg->char_id);
+ break;
+ case 2: //account reg
+ sprintf (tmp_sql, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'",reg_db, reg->account_id);
+ break;
+ case 1: //account2 reg
+ ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n");
+ return 0;
+ }
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+
+ if (sql_res) {
+ for(j=0;(sql_row = mysql_fetch_row(sql_res));j++){
+ strcpy(reg->reg[j].str, sql_row[0]);
+ strcpy(reg->reg[j].value, sql_row[1]);
+ }
+ mysql_free_result(sql_res);
+ }
+ reg->reg_num=j;
+ return 1;
+}
+
+// Initialize
+int inter_accreg_sql_init(void)
+{
+ CREATE(accreg_pt, struct accreg, 1);
+ return 0;
+
+}
+#endif //TXT_SQL_CONVERT
+
+/*==========================================
+ * read config file
+ *------------------------------------------
+ */
+static int inter_config_read(const char *cfgName) {
+ int i;
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ fp=fopen(cfgName,"r");
+ if(fp==NULL){
+ ShowError("file not found: %s\n", cfgName);
+ return 1;
+ }
+
+ ShowInfo("reading file %s...\n",cfgName);
+
+ while(fgets(line, 1020, fp)){
+ i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
+ if(i!=2)
+ continue;
+
+ if(strcmpi(w1,"char_server_ip")==0){
+ strcpy(char_server_ip, w2);
+ ShowStatus ("set char_server_ip : %s\n",w2);
+ }
+ else if(strcmpi(w1,"char_server_port")==0){
+ char_server_port=atoi(w2);
+ ShowStatus ("set char_server_port : %s\n",w2);
+ }
+ else if(strcmpi(w1,"char_server_id")==0){
+ strcpy(char_server_id, w2);
+ ShowStatus ("set char_server_id : %s\n",w2);
+ }
+ else if(strcmpi(w1,"char_server_pw")==0){
+ strcpy(char_server_pw, w2);
+ ShowStatus ("set char_server_pw : %s\n",w2);
+ }
+ else if(strcmpi(w1,"char_server_db")==0){
+ strcpy(char_server_db, w2);
+ ShowStatus ("set char_server_db : %s\n",w2);
+ }
+ else if(strcmpi(w1,"default_codepage")==0){
+ strcpy(default_codepage, w2);
+ ShowStatus ("set default_codepage : %s\n",w2);
+ }
+ //Logins information to be read from the inter_athena.conf
+ //for character deletion (checks email in the loginDB)
+ else if(strcmpi(w1,"login_server_ip")==0){
+ strcpy(login_server_ip, w2);
+ ShowStatus ("set login_server_ip : %s\n",w2);
+ }
+ else if(strcmpi(w1,"login_server_port")==0){
+ login_server_port=atoi(w2);
+ ShowStatus ("set login_server_port : %s\n",w2);
+ }
+ else if(strcmpi(w1,"login_server_id")==0){
+ strcpy(login_server_id, w2);
+ ShowStatus ("set login_server_id : %s\n",w2);
+ }
+ else if(strcmpi(w1,"login_server_pw")==0){
+ strcpy(login_server_pw, w2);
+ ShowStatus ("set login_server_pw : %s\n",w2);
+ }
+ else if(strcmpi(w1,"login_server_db")==0){
+ strcpy(login_server_db, w2);
+ ShowStatus ("set login_server_db : %s\n",w2);
+ }
+#ifndef TXT_SQL_CONVERT
+ else if(strcmpi(w1,"party_share_level")==0){
+ party_share_level=(unsigned int)atof(w2);
+ }
+ else if(strcmpi(w1,"log_inter")==0){
+ log_inter = atoi(w2);
+ }
+ else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza]
+ strcpy(main_chat_nick, w2); //
+ }
+#endif //TXT_SQL_CONVERT
+ else if(strcmpi(w1,"import")==0){
+ inter_config_read(w2);
+ }
+ }
+ fclose(fp);
+
+ ShowInfo ("done reading %s.\n", cfgName);
+
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+
+// Save interlog into sql
+int inter_log(char *fmt,...)
+{
+ char str[255];
+ char temp_str[510]; //Needs be twice as long as str[] //Skotlex
+ va_list ap;
+ va_start(ap,fmt);
+
+ vsprintf(str,fmt,ap);
+ sprintf(tmp_sql,"INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')",interlog_db, jstrescapecpy(temp_str,str));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ va_end(ap);
+ return 0;
+}
+
+/*======================================================
+ * Does a mysql_ping to all connection handles. [Skotlex]
+ *------------------------------------------------------
+ */
+int inter_sql_ping(int tid, unsigned int tick, int id, int data)
+{
+ ShowInfo("Pinging SQL server to keep connection alive...\n");
+ mysql_ping(&mysql_handle);
+ if(char_gm_read)
+ mysql_ping(&lmysql_handle);
+ return 0;
+}
+#endif //TXT_SQL_CONVERT
+
+// initialize
+int inter_init_sql(const char *file)
+{
+ //int i;
+
+ ShowInfo ("interserver initialize...\n");
+ inter_config_read(file);
+
+ //DB connection initialized
+ mysql_init(&mysql_handle);
+ ShowInfo("Connect Character DB server.... (Character Server)\n");
+ if(!mysql_real_connect(&mysql_handle, char_server_ip, char_server_id, char_server_pw,
+ char_server_db ,char_server_port, (char *)NULL, 0)) {
+ //pointer check
+ ShowFatalError("%s\n",mysql_error(&mysql_handle));
+ exit(1);
+ }
+#ifndef TXT_SQL_CONVERT
+ else if (inter_sql_test()) {
+ ShowStatus("Connect Success! (Character Server)\n");
+ }
+
+ if(char_gm_read) {
+ mysql_init(&lmysql_handle);
+ ShowInfo("Connect Character DB server.... (login server)\n");
+ if(!mysql_real_connect(&lmysql_handle, login_server_ip, login_server_id, login_server_pw,
+ login_server_db ,login_server_port, (char *)NULL, 0)) {
+ //pointer check
+ ShowFatalError("%s\n",mysql_error(&lmysql_handle));
+ exit(1);
+ }else {
+ ShowStatus ("Connect Success! (Login Server)\n");
+ }
+ }
+#endif //TXT_SQL_CONVERT
+ if(strlen(default_codepage) > 0 ) {
+ sprintf( tmp_sql, "SET NAMES %s", default_codepage );
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+#ifndef TXT_SQL_CONVERT
+ if(char_gm_read)
+ if (mysql_query(&lmysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&lmysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+#endif //TXT_SQL_CONVERT
+ }
+
+#ifndef TXT_SQL_CONVERT
+ wis_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+ inter_guild_sql_init();
+ inter_storage_sql_init();
+ inter_party_sql_init();
+ inter_pet_sql_init();
+ inter_homunculus_sql_init(); // albator
+ inter_accreg_sql_init();
+
+ if (connection_ping_interval) {
+ add_timer_func_list(inter_sql_ping, "inter_sql_ping");
+ add_timer_interval(gettick()+connection_ping_interval*60*60*1000,
+ inter_sql_ping, 0, 0, connection_ping_interval*60*60*1000);
+ }
+#endif //TXT_SQL_CONVERT
+ return 0;
+}
+#ifndef TXT_SQL_CONVERT
+
+int inter_sql_test (void)
+{
+ const char fields[][24] = {
+ "father", // version 1363
+ "fame", // version 1491
+ };
+ char buf[1024] = "";
+ int i;
+
+ sprintf(tmp_sql, "EXPLAIN `%s`",char_db);
+ if (mysql_query(&mysql_handle, tmp_sql)) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ // store DB fields
+ if (sql_res) {
+ while((sql_row = mysql_fetch_row(sql_res))) {
+ strcat (buf, sql_row[0]);
+ strcat (buf, " ");
+ }
+ }
+
+ // check DB strings
+ for (i = 0; i < (int)(sizeof(fields) / sizeof(fields[0])); i++) {
+ if(!strstr(buf, fields[i])) {
+ ShowSQL ("Field `%s` not be found in `%s`. Consider updating your database!\n", fields[i], char_db);
+ exit(1);
+ }
+ }
+
+ mysql_free_result(sql_res);
+
+ return 1;
+}
+
+// finalize
+void inter_final(void) {
+ wis_db->destroy(wis_db, NULL);
+
+ inter_guild_sql_final();
+ inter_storage_sql_final();
+ inter_party_sql_final();
+ inter_pet_sql_final();
+ inter_homunculus_sql_final(); //[orn]
+
+ if (accreg_pt) aFree(accreg_pt);
+ return;
+}
+
+int inter_mapif_init(int fd) {
+ inter_guild_mapif_init(fd);
+
+ return 0;
+}
+
+
+//--------------------------------------------------------
+
+// GM message sending
+int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) {
+ unsigned char buf[2048];
+
+ if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex]
+ WBUFW(buf, 0) = 0x3800;
+ WBUFW(buf, 2) = len;
+ WBUFL(buf, 4) = color;
+ memcpy(WBUFP(buf, 8), mes, len-8);
+ mapif_sendallwos(sfd, buf, len);
+ return 0;
+}
+
+// Wis sending
+int mapif_wis_message(struct WisData *wd) {
+ unsigned char buf[2048];
+ if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex]
+
+ WBUFW(buf, 0) = 0x3801;
+ WBUFW(buf, 2) = 56 +wd->len;
+ WBUFL(buf, 4) = wd->id;
+ memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH);
+ memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH);
+ memcpy(WBUFP(buf,56), wd->msg, wd->len);
+ wd->count = mapif_sendall(buf,WBUFW(buf,2));
+
+ return 0;
+}
+// Wis sending result
+int mapif_wis_end(struct WisData *wd,int flag)
+{
+ unsigned char buf[27];
+
+ WBUFW(buf, 0)=0x3802;
+ memcpy(WBUFP(buf, 2),wd->src,24);
+ WBUFB(buf,26)=flag;
+ mapif_send(wd->fd,buf,27);
+// printf("inter server wis_end %d\n",flag);
+ return 0;
+}
+
+int mapif_account_reg(int fd,unsigned char *src)
+{
+// unsigned char buf[WBUFW(src,2)]; <- Hey, can this really be done? [Skotlex]
+ unsigned char *buf = aCalloc(1,WBUFW(src,2)); // [Lance] - Skot... Dynamic allocation is better :D
+ memcpy(WBUFP(buf,0),src,WBUFW(src,2));
+ WBUFW(buf, 0)=0x3804;
+ mapif_sendallwos(fd, buf, WBUFW(buf,2));
+ aFree(buf);
+ return 0;
+}
+
+// Send the requested account_reg
+int mapif_account_reg_reply(int fd,int account_id,int char_id, int type)
+{
+ struct accreg *reg=accreg_pt;
+ WFIFOHEAD(fd, 13 + 5000);
+ inter_accreg_fromsql(account_id,char_id,reg,type);
+
+ WFIFOW(fd,0)=0x3804;
+ WFIFOL(fd,4)=account_id;
+ WFIFOL(fd,8)=char_id;
+ WFIFOB(fd,12)=type;
+ if(reg->reg_num==0){
+ WFIFOW(fd,2)=13;
+ }else{
+ int i,p;
+ for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) {
+ p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place.
+ p+= sprintf(WFIFOP(fd,p), "%s", reg->reg[i].value)+1;
+ }
+ WFIFOW(fd,2)=p;
+ if (p>= 5000)
+ ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id);
+ }
+ WFIFOSET(fd,WFIFOW(fd,2));
+ return 0;
+}
+
+int mapif_send_gmaccounts()
+{
+ int i, len = 4;
+ unsigned char buf[32000];
+
+ // forward the gm accounts to the map server
+ len = 4;
+ WBUFW(buf,0) = 0x2b15;
+
+ for(i = 0; i < GM_num; i++) {
+ WBUFL(buf, len) = gm_account[i].account_id;
+ WBUFB(buf, len+4) = (unsigned char)gm_account[i].level;
+ len += 5;
+ }
+ WBUFW(buf, 2) = len;
+ mapif_sendall(buf, len);
+
+ return 0;
+}
+
+//Sends to map server the current max Account/Char id [Skotlex]
+void mapif_send_maxid(int account_id, int char_id)
+{
+ unsigned char buf[12];
+
+ WBUFW(buf,0) = 0x2b07;
+ WBUFL(buf,2) = account_id;
+ WBUFL(buf,6) = char_id;
+ mapif_sendall(buf, 10);
+}
+
+//Request to kick char from a certain map server. [Skotlex]
+int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason)
+{
+ if (fd >= 0)
+ {
+ WFIFOHEAD(fd,7);
+ WFIFOW(fd,0) = 0x2b1f;
+ WFIFOL(fd,2) = account_id;
+ WFIFOB(fd,6) = reason;
+ WFIFOSET(fd,7);
+ return 0;
+ }
+ return -1;
+}
+
+//--------------------------------------------------------
+
+// Existence check of WISP data
+int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) {
+ unsigned long tick;
+ struct WisData *wd = (struct WisData *)data;
+ tick = va_arg(ap, unsigned long);
+
+ if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX)
+ wis_dellist[wis_delnum++] = wd->id;
+
+ return 0;
+}
+
+int check_ttl_wisdata(void) {
+ unsigned long tick = gettick();
+ int i;
+
+ do {
+ wis_delnum = 0;
+ wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick);
+ for(i = 0; i < wis_delnum; i++) {
+ struct WisData *wd = idb_get(wis_db, wis_dellist[i]);
+ ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst);
+ // removed. not send information after a timeout. Just no answer for the player
+ //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ idb_remove(wis_db, wd->id);
+ }
+ } while(wis_delnum >= WISDELLIST_MAX);
+
+ return 0;
+}
+
+//--------------------------------------------------------
+
+// GM message sending
+int mapif_parse_GMmessage(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_GMmessage(RFIFOP(fd, 8), RFIFOW(fd, 2), RFIFOL(fd, 4), fd);
+ return 0;
+}
+
+
+// Wisp/page request to send
+int mapif_parse_WisRequest(int fd) {
+ struct WisData* wd;
+ static int wisid = 0;
+ char name[NAME_LENGTH], t_name[NAME_LENGTH*2]; //Needs space to allocate names with escaped chars [Skotlex]
+ RFIFOHEAD(fd);
+ if ( fd <= 0 ) {return 0;} // check if we have a valid fd
+
+ if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) {
+ ShowWarning("inter: Wis message size too long.\n");
+ return 0;
+ } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows...
+ ShowError("inter: Wis message doesn't exist.\n");
+ return 0;
+ }
+ memcpy(name, RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex]
+ name[NAME_LENGTH-1]= '\0';
+
+ sprintf (tmp_sql, "SELECT `name` FROM `%s` WHERE `name`='%s'",
+ char_db, jstrescapecpy(t_name, name));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+
+ // search if character exists before to ask all map-servers
+ if (!(sql_row = mysql_fetch_row(sql_res))) {
+ unsigned char buf[27];
+ WBUFW(buf, 0) = 0x3802;
+ memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH);
+ WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ mapif_send(fd, buf, 27);
+ // Character exists. So, ask all map-servers
+ } else {
+ // to be sure of the correct name, rewrite it
+ memset(name, 0, NAME_LENGTH);
+ strncpy(name, sql_row[0], NAME_LENGTH);
+ // if source is destination, don't ask other servers.
+ if (strcmp((char*)RFIFOP(fd,4),name) == 0) {
+ unsigned char buf[27];
+ WBUFW(buf, 0) = 0x3802;
+ memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH);
+ WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ mapif_send(fd, buf, 27);
+ } else {
+
+ CREATE(wd, struct WisData, 1);
+
+ // Whether the failure of previous wisp/page transmission (timeout)
+ check_ttl_wisdata();
+
+ wd->id = ++wisid;
+ wd->fd = fd;
+ wd->len= RFIFOW(fd,2)-52;
+ memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH);
+ memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH);
+ memcpy(wd->msg, RFIFOP(fd,52), wd->len);
+ wd->tick = gettick();
+ idb_put(wis_db, wd->id, wd);
+ mapif_wis_message(wd);
+ }
+ }
+
+ //Freeing ... O.o
+ if(sql_res){
+ mysql_free_result(sql_res);
+ }
+
+ return 0;
+}
+
+
+// Wisp/page transmission result
+int mapif_parse_WisReply(int fd) {
+ int id, flag;
+ struct WisData *wd;
+ RFIFOHEAD(fd);
+ id = RFIFOL(fd,2);
+ flag = RFIFOB(fd,6);
+ wd = idb_get(wis_db, id);
+ if (wd == NULL)
+ return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server
+
+ if ((--wd->count) <= 0 || flag != 1) {
+ mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
+ idb_remove(wis_db, id);
+ }
+
+ return 0;
+}
+
+// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers)
+int mapif_parse_WisToGM(int fd) {
+ unsigned char buf[2048]; // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
+ RFIFOHEAD(fd);
+ ShowDebug("Sent packet back!\n");
+ memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2));
+ WBUFW(buf, 0) = 0x3803;
+ mapif_sendall(buf, RFIFOW(fd,2));
+
+ return 0;
+}
+
+// Save account_reg into sql (type=2)
+int mapif_parse_Registry(int fd)
+{
+ int j,p,len, max;
+ struct accreg *reg=accreg_pt;
+ RFIFOHEAD(fd);
+ memset(accreg_pt,0,sizeof(struct accreg));
+ switch (RFIFOB(fd, 12)) {
+ case 3: //Character registry
+ max = GLOBAL_REG_NUM;
+ break;
+ case 2: //Account Registry
+ max = ACCOUNT_REG_NUM;
+ break;
+ case 1: //Account2 registry, must be sent over to login server.
+ return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4);
+ default:
+ return 1;
+ }
+ for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){
+ sscanf(RFIFOP(fd,p), "%31c%n",reg->reg[j].str,&len);
+ reg->reg[j].str[len]='\0';
+ p +=len+1; //+1 to skip the '\0' between strings.
+ sscanf(RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len);
+ reg->reg[j].value[len]='\0';
+ p +=len+1;
+ }
+ reg->reg_num=j;
+
+ inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12));
+ mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers.
+ return 0;
+}
+
+// Request the value of all registries.
+int mapif_parse_RegistryRequest(int fd)
+{
+ RFIFOHEAD(fd);
+ //Load Char Registry
+ if (RFIFOB(fd,12))
+ mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3);
+ //Load Account Registry
+ if (RFIFOB(fd,11))
+ mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2);
+ //Ask Login Server for Account2 values.
+ if (RFIFOB(fd,10))
+ request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2);
+ return 1;
+}
+
+//--------------------------------------------------------
+int inter_parse_frommap(int fd)
+{
+ int cmd;
+ int len=0;
+ RFIFOHEAD(fd);
+ cmd=RFIFOW(fd,0);
+ // interŽIŠΗŠ‚©‚𒲂ׂ
+ if(cmd < 0x3000 || cmd >= 0x3000 + (sizeof(inter_recv_packet_length)/
+ sizeof(inter_recv_packet_length[0]) ) )
+ return 0;
+
+ if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex]
+ return 0;
+
+ // ƒpƒPƒbƒg’·‚𒲂ׂι
+ if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0)
+ return 2;
+
+ switch(cmd){
+ case 0x3000: mapif_parse_GMmessage(fd); break;
+ case 0x3001: mapif_parse_WisRequest(fd); break;
+ case 0x3002: mapif_parse_WisReply(fd); break;
+ case 0x3003: mapif_parse_WisToGM(fd); break;
+ case 0x3004: mapif_parse_Registry(fd); break;
+ case 0x3005: mapif_parse_RegistryRequest(fd); break;
+ default:
+ if(inter_party_parse_frommap(fd))
+ break;
+ if(inter_guild_parse_frommap(fd))
+ break;
+ if(inter_storage_parse_frommap(fd))
+ break;
+ if(inter_pet_parse_frommap(fd))
+ break;
+ if(inter_homunculus_parse_frommap(fd)) //albator
+ break;
+ return 0;
+ }
+
+ RFIFOSKIP(fd, len);
+ return 1;
+}
+
+// RFIFO check
+int inter_check_length(int fd, int length)
+{
+ RFIFOHEAD(fd);
+ if(length==-1){ // v-len packet
+ if(RFIFOREST(fd)<4) // packet not yet
+ return 0;
+ length = RFIFOW(fd, 2);
+ }
+
+ if((int)RFIFOREST(fd) < length) // packet not yet
+ return 0;
+
+ return length;
+}
+#endif //TXT_SQL_CONVERT
diff --git a/src/char_sql/inter.h b/src/char_sql/inter.h
index 8dc6f3668..ecfde71c0 100644
--- a/src/char_sql/inter.h
+++ b/src/char_sql/inter.h
@@ -1,56 +1,56 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _INTER_SQL_H_
-#define _INTER_SQL_H_
-
-int inter_init_sql(const char *file);
-void inter_final(void);
-int inter_parse_frommap(int fd);
-int inter_mapif_init(int fd);
-int mapif_send_gmaccounts(void);
-void mapif_send_maxid(int, int);
-int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason);
-
-int inter_check_length(int fd,int length);
-
-int inter_log(char *fmt,...);
-
-#define inter_cfgName "conf/inter_athena.conf"
-
-extern unsigned int party_share_level;
-extern char inter_log_filename[1024];
-
-#ifdef __WIN32
-//Windows.h need to be included before mysql.h
-#include <windows.h>
-#endif
-//add include for DBMS(mysql)
-#include <mysql.h>
-
-extern MYSQL mysql_handle;
-extern char tmp_sql[65535];
-extern MYSQL_RES* sql_res ;
-extern MYSQL_ROW sql_row ;
-extern int sql_cnt;
-
-extern MYSQL lmysql_handle;
-extern MYSQL_RES* lsql_res ;
-extern MYSQL_ROW lsql_row ;
-
-extern int char_server_port;
-extern char char_server_ip[32];
-extern char char_server_id[32];
-extern char char_server_pw[32];
-extern char char_server_db[32];
-
-extern int login_db_server_port;
-extern char login_db_server_ip[32];
-extern char login_db_server_id[32];
-extern char login_db_server_pw[32];
-extern char login_db_server_db[32];
-
-extern char main_chat_nick[16];
-
-int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INTER_SQL_H_
+#define _INTER_SQL_H_
+
+int inter_init_sql(const char *file);
+void inter_final(void);
+int inter_parse_frommap(int fd);
+int inter_mapif_init(int fd);
+int mapif_send_gmaccounts(void);
+void mapif_send_maxid(int, int);
+int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason);
+
+int inter_check_length(int fd,int length);
+
+int inter_log(char *fmt,...);
+
+#define inter_cfgName "conf/inter_athena.conf"
+
+extern unsigned int party_share_level;
+extern char inter_log_filename[1024];
+
+#ifdef __WIN32
+//Windows.h need to be included before mysql.h
+#include <windows.h>
+#endif
+//add include for DBMS(mysql)
+#include <mysql.h>
+
+extern MYSQL mysql_handle;
+extern char tmp_sql[65535];
+extern MYSQL_RES* sql_res ;
+extern MYSQL_ROW sql_row ;
+extern int sql_cnt;
+
+extern MYSQL lmysql_handle;
+extern MYSQL_RES* lsql_res ;
+extern MYSQL_ROW lsql_row ;
+
+extern int char_server_port;
+extern char char_server_ip[32];
+extern char char_server_id[32];
+extern char char_server_pw[32];
+extern char char_server_db[32];
+
+extern int login_db_server_port;
+extern char login_db_server_ip[32];
+extern char login_db_server_id[32];
+extern char login_db_server_pw[32];
+extern char login_db_server_db[32];
+
+extern char main_chat_nick[16];
+
+int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
+#endif
diff --git a/src/char_sql/itemdb.c b/src/char_sql/itemdb.c
index e3d37ca85..9f76eb21c 100644
--- a/src/char_sql/itemdb.c
+++ b/src/char_sql/itemdb.c
@@ -1,222 +1,222 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "itemdb.h"
-#include "db.h"
-#include "inter.h"
-#include "char.h"
-#include "utils.h"
-#include "../common/showmsg.h"
-
-#define MAX_RANDITEM 2000
-
-// ** ITEMDB_OVERRIDE_NAME_VERBOSE **
-// ’θ‹`‚·‚ι‚ƁAitemdb.txt‚Ζgrf‚Ε–Ό‘O‚ͺˆΩ‚Θ‚ικ‡A•\Ž¦‚΅‚ά‚·.
-//#define ITEMDB_OVERRIDE_NAME_VERBOSE 1
-
-char item_db_db[256]="item_db"; // added to specify item_db sql table [Valaris]
-char item_db2_db[256]="item_db2";
-
-static struct dbt* item_db;
-
-static void* create_item(DBKey key, va_list args) {
- struct item_data *id;
- int nameid = key.i;
- CREATE(id, struct item_data, 1);
- id->nameid = nameid;
- id->type = IT_ETC;
- return id;
-}
-/*==========================================
- * DB‚ΜŒŸυ
- *------------------------------------------
- */
-struct item_data* itemdb_search(int nameid)
-{
- return idb_ensure(item_db,nameid,create_item);
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-int itemdb_isequip(int nameid)
-{
- int type=itemdb_type(nameid);
- if(type==IT_HEALING || type==IT_USABLE || type==IT_ETC || type==IT_CARD || type==IT_AMMO)
- return 0;
- return 1;
-}
-/*==========================================
- *
- *------------------------------------------
- */
-int itemdb_isequip2(struct item_data *data)
-{
- if(data) {
- int type=data->type;
- if(type==IT_HEALING || type==IT_USABLE || type==IT_ETC || type==IT_CARD || type==IT_AMMO)
- return 0;
- else
- return 1;
- }
- return 0;
-}
-
-
-
-/*==========================================
- * ƒAƒCƒeƒ€ƒf[ƒ^ƒx[ƒX‚̓ǂݍž‚έ
- *------------------------------------------
- */
-static int itemdb_readdb(void)
-{
- FILE *fp;
- char line[1024];
- int ln=0,lines=0;
- int nameid,j;
- char *str[32],*p,*np;
- struct item_data *id;
- int i=0;
- char *filename[]={ "item_db.txt","item_db2.txt" };
-
- for(i=0;i<2;i++){
- sprintf(line, "%s/%s", db_path, filename[i]);
- fp=fopen(line,"r");
- if(fp==NULL){
- if(i>0)
- continue;
- ShowFatalError("can't read %s\n",line);
- exit(1);
- }
-
- lines=0;
- while(fgets(line,1020,fp)){
- lines++;
- if(line[0]=='/' && line[1]=='/')
- continue;
- malloc_tsetdword(str,0,sizeof(str));
- for(j=0,np=p=line;j<4 && p;j++){
- str[j]=p;
- p=strchr(p,',');
- if(p){ *p++=0; np=p; }
- }
- if(str[0]==NULL)
- continue;
-
- nameid=atoi(str[0]);
- if(nameid<=0)
- continue;
- if (j < 4)
- { //Crash-fix on broken item lines. [Skotlex]
- ShowWarning("Reading %s: Insufficient fields for item with id %d, skipping.\n", filename[i], nameid);
- continue;
- }
- ln++;
-
- //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
- id=itemdb_search(nameid);
- strncpy(id->name, str[1], ITEM_NAME_LENGTH-1);
- strncpy(id->jname, str[2], ITEM_NAME_LENGTH-1);
- id->type=atoi(str[3]);
- if (id->type == IT_DELAYCONSUME)
- id->type = IT_USABLE;
- }
- fclose(fp);
- if (ln > 0) {
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,filename[i]);
- }
- ln=0; // reset to 0
- }
- return 0;
-}
-
-static int itemdb_read_sqldb(void) // sql item_db read, shortened version of map-server item_db read [Valaris]
-{
- unsigned short nameid;
- struct item_data *id;
- char *item_db_name[] = { item_db_db, item_db2_db };
- long unsigned int ln = 0;
- int i;
-
- // ----------
-
- for (i = 0; i < 2; i++) {
- sprintf(tmp_sql, "SELECT * FROM `%s`", item_db_name[i]);
-
- // Execute the query; if the query execution succeeded...
- if (mysql_query(&mysql_handle, tmp_sql) == 0) {
- sql_res = mysql_store_result(&mysql_handle);
-
- // If the storage of the query result succeeded...
- if (sql_res) {
- // Parse each row in the query result into sql_row
- while ((sql_row = mysql_fetch_row(sql_res)))
- { /*Table structure is:
- 00 id
- 01 name_english
- 02 name_japanese
- 03 type
- ...
- */
- nameid = atoi(sql_row[0]);
-
- // If the identifier is not within the valid range, process the next row
- if (nameid == 0)
- continue;
-
- ln++;
-
- // ----------
- id=itemdb_search(nameid);
-
- strncpy(id->name, sql_row[1], ITEM_NAME_LENGTH-1);
- strncpy(id->jname, sql_row[2], ITEM_NAME_LENGTH-1);
-
- id->type = atoi(sql_row[3]);
- if (id->type == IT_DELAYCONSUME)
- id->type = IT_USABLE;
- }
- ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, item_db_name[i]);
- ln = 0;
- } else {
- ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
-
- // Free the query result
- mysql_free_result(sql_res);
- } else {
- ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mysql_handle));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- }
- }
-
- return 0;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-void do_final_itemdb(void)
-{
- if(item_db){
- item_db->destroy(item_db,NULL);
- item_db=NULL;
- }
-}
-int do_init_itemdb(void)
-{
- item_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
-
- if (db_use_sqldbs) // it db_use_sqldbs in inter config are yes, will read from item_db for char server display [Valaris]
- itemdb_read_sqldb();
- else
- itemdb_readdb();
- return 0;
-}
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "itemdb.h"
+#include "db.h"
+#include "inter.h"
+#include "char.h"
+#include "utils.h"
+#include "../common/showmsg.h"
+
+#define MAX_RANDITEM 2000
+
+// ** ITEMDB_OVERRIDE_NAME_VERBOSE **
+// ’θ‹`‚·‚ι‚ƁAitemdb.txt‚Ζgrf‚Ε–Ό‘O‚ͺˆΩ‚Θ‚ικ‡A•\Ž¦‚΅‚ά‚·.
+//#define ITEMDB_OVERRIDE_NAME_VERBOSE 1
+
+char item_db_db[256]="item_db"; // added to specify item_db sql table [Valaris]
+char item_db2_db[256]="item_db2";
+
+static struct dbt* item_db;
+
+static void* create_item(DBKey key, va_list args) {
+ struct item_data *id;
+ int nameid = key.i;
+ CREATE(id, struct item_data, 1);
+ id->nameid = nameid;
+ id->type = IT_ETC;
+ return id;
+}
+/*==========================================
+ * DB‚ΜŒŸυ
+ *------------------------------------------
+ */
+struct item_data* itemdb_search(int nameid)
+{
+ return idb_ensure(item_db,nameid,create_item);
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int itemdb_isequip(int nameid)
+{
+ int type=itemdb_type(nameid);
+ if(type==IT_HEALING || type==IT_USABLE || type==IT_ETC || type==IT_CARD || type==IT_AMMO)
+ return 0;
+ return 1;
+}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int itemdb_isequip2(struct item_data *data)
+{
+ if(data) {
+ int type=data->type;
+ if(type==IT_HEALING || type==IT_USABLE || type==IT_ETC || type==IT_CARD || type==IT_AMMO)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/*==========================================
+ * ƒAƒCƒeƒ€ƒf[ƒ^ƒx[ƒX‚̓ǂݍž‚έ
+ *------------------------------------------
+ */
+static int itemdb_readdb(void)
+{
+ FILE *fp;
+ char line[1024];
+ int ln=0,lines=0;
+ int nameid,j;
+ char *str[32],*p,*np;
+ struct item_data *id;
+ int i=0;
+ char *filename[]={ "item_db.txt","item_db2.txt" };
+
+ for(i=0;i<2;i++){
+ sprintf(line, "%s/%s", db_path, filename[i]);
+ fp=fopen(line,"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ ShowFatalError("can't read %s\n",line);
+ exit(1);
+ }
+
+ lines=0;
+ while(fgets(line,1020,fp)){
+ lines++;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ malloc_tsetdword(str,0,sizeof(str));
+ for(j=0,np=p=line;j<4 && p;j++){
+ str[j]=p;
+ p=strchr(p,',');
+ if(p){ *p++=0; np=p; }
+ }
+ if(str[0]==NULL)
+ continue;
+
+ nameid=atoi(str[0]);
+ if(nameid<=0)
+ continue;
+ if (j < 4)
+ { //Crash-fix on broken item lines. [Skotlex]
+ ShowWarning("Reading %s: Insufficient fields for item with id %d, skipping.\n", filename[i], nameid);
+ continue;
+ }
+ ln++;
+
+ //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
+ id=itemdb_search(nameid);
+ strncpy(id->name, str[1], ITEM_NAME_LENGTH-1);
+ strncpy(id->jname, str[2], ITEM_NAME_LENGTH-1);
+ id->type=atoi(str[3]);
+ if (id->type == IT_DELAYCONSUME)
+ id->type = IT_USABLE;
+ }
+ fclose(fp);
+ if (ln > 0) {
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,filename[i]);
+ }
+ ln=0; // reset to 0
+ }
+ return 0;
+}
+
+static int itemdb_read_sqldb(void) // sql item_db read, shortened version of map-server item_db read [Valaris]
+{
+ unsigned short nameid;
+ struct item_data *id;
+ char *item_db_name[] = { item_db_db, item_db2_db };
+ long unsigned int ln = 0;
+ int i;
+
+ // ----------
+
+ for (i = 0; i < 2; i++) {
+ sprintf(tmp_sql, "SELECT * FROM `%s`", item_db_name[i]);
+
+ // Execute the query; if the query execution succeeded...
+ if (mysql_query(&mysql_handle, tmp_sql) == 0) {
+ sql_res = mysql_store_result(&mysql_handle);
+
+ // If the storage of the query result succeeded...
+ if (sql_res) {
+ // Parse each row in the query result into sql_row
+ while ((sql_row = mysql_fetch_row(sql_res)))
+ { /*Table structure is:
+ 00 id
+ 01 name_english
+ 02 name_japanese
+ 03 type
+ ...
+ */
+ nameid = atoi(sql_row[0]);
+
+ // If the identifier is not within the valid range, process the next row
+ if (nameid == 0)
+ continue;
+
+ ln++;
+
+ // ----------
+ id=itemdb_search(nameid);
+
+ strncpy(id->name, sql_row[1], ITEM_NAME_LENGTH-1);
+ strncpy(id->jname, sql_row[2], ITEM_NAME_LENGTH-1);
+
+ id->type = atoi(sql_row[3]);
+ if (id->type == IT_DELAYCONSUME)
+ id->type = IT_USABLE;
+ }
+ ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, item_db_name[i]);
+ ln = 0;
+ } else {
+ ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+
+ // Free the query result
+ mysql_free_result(sql_res);
+ } else {
+ ShowSQL("DB error (%s) - %s\n",item_db_name[i], mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void do_final_itemdb(void)
+{
+ if(item_db){
+ item_db->destroy(item_db,NULL);
+ item_db=NULL;
+ }
+}
+int do_init_itemdb(void)
+{
+ item_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+
+ if (db_use_sqldbs) // it db_use_sqldbs in inter config are yes, will read from item_db for char server display [Valaris]
+ itemdb_read_sqldb();
+ else
+ itemdb_readdb();
+ return 0;
+}
diff --git a/src/char_sql/itemdb.h b/src/char_sql/itemdb.h
index d19dd498c..53b1d3e02 100644
--- a/src/char_sql/itemdb.h
+++ b/src/char_sql/itemdb.h
@@ -1,43 +1,43 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#ifndef _ITEMDB_H_
-#define _ITEMDB_H_
-#include "mmo.h"
-
-//FIXME: Maybe it would be better to move this enum to mmo.h,
-//instead of having it twice on the map server and here? [Skotlex]
-enum {
- IT_HEALING = 0,
- IT_UNKNOWN, //1
- IT_USABLE, //2
- IT_ETC, //3
- IT_WEAPON, //4
- IT_ARMOR, //5
- IT_CARD, //6
- IT_PETEGG, //7
- IT_PETARMOR,//8
- IT_UNKNOWN2,//9
- IT_AMMO, //10
- IT_DELAYCONSUME,//11
- IT_MAX
-} item_types;
-
-struct item_data {
- int nameid;
- char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH];
- int type;
-};
-
-extern char item_db_db[256];
-extern char item_db2_db[256];
-struct item_data* itemdb_search(int nameid);
-#define itemdb_type(n) itemdb_search(n)->type
-
-int itemdb_isequip(int);
-int itemdb_isequip2(struct item_data *);
-
-void do_final_itemdb(void);
-int do_init_itemdb(void);
-
-#endif
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _ITEMDB_H_
+#define _ITEMDB_H_
+#include "mmo.h"
+
+//FIXME: Maybe it would be better to move this enum to mmo.h,
+//instead of having it twice on the map server and here? [Skotlex]
+enum {
+ IT_HEALING = 0,
+ IT_UNKNOWN, //1
+ IT_USABLE, //2
+ IT_ETC, //3
+ IT_WEAPON, //4
+ IT_ARMOR, //5
+ IT_CARD, //6
+ IT_PETEGG, //7
+ IT_PETARMOR,//8
+ IT_UNKNOWN2,//9
+ IT_AMMO, //10
+ IT_DELAYCONSUME,//11
+ IT_MAX
+} item_types;
+
+struct item_data {
+ int nameid;
+ char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH];
+ int type;
+};
+
+extern char item_db_db[256];
+extern char item_db2_db[256];
+struct item_data* itemdb_search(int nameid);
+#define itemdb_type(n) itemdb_search(n)->type
+
+int itemdb_isequip(int);
+int itemdb_isequip2(struct item_data *);
+
+void do_final_itemdb(void);
+int do_init_itemdb(void);
+
+#endif