// $Id: chrif.c,v 1.6 2004/09/25 11:39:17 MouseJstr Exp $ #include #include #include #ifdef LCCWIN32 #include #else #include #include #include #include #endif #include #include #include "../common/socket.hpp" #include "../common/timer.hpp" #include "map.hpp" #include "battle.hpp" #include "chrif.hpp" #include "clif.hpp" #include "intif.hpp" #include "npc.hpp" #include "pc.hpp" #include "../common/nullpo.hpp" #include "itemdb.hpp" #ifdef MEMWATCH #include "memwatch.hpp" #endif static const int packet_len_table[0x20] = { 60, 3, 10, 27, 22, -1, 6, -1, // 2af8-2aff 6, -1, 18, 7, -1, 49, 44, 0, // 2b00-2b07 6, 30, -1, 10, 86, 7, 44, 34, // 2b08-2b0f -1, -1, 10, 6, 11, -1, 0, 0, // 2b10-2b17 }; int char_fd; int srvinfo; static char char_ip_str[16]; static int char_ip; static int char_port = 6121; static char userid[24], passwd[24]; static int chrif_state; // 設定ファイル読み込み関係 /*========================================== * *------------------------------------------ */ void chrif_setuserid(char *id) { strncpy(userid, id, sizeof(userid)-1); userid[sizeof(userid)-1] = '\0'; } /*========================================== * *------------------------------------------ */ void chrif_setpasswd(char *pwd) { strncpy(passwd, pwd, sizeof(passwd)-1); passwd[sizeof(passwd)-1] = '\0'; } char *chrif_getpasswd(void) { return passwd; } /*========================================== * *------------------------------------------ */ void chrif_setip(char *ip) { strncpy(char_ip_str, ip, sizeof(char_ip_str)-1); char_ip_str[sizeof(char_ip_str)-1] = '\0'; char_ip = inet_addr(char_ip_str); } /*========================================== * *------------------------------------------ */ void chrif_setport(int port) { char_port = port; } /*========================================== * *------------------------------------------ */ int chrif_isconnect(void) { return chrif_state == 2; } /*========================================== * *------------------------------------------ */ int chrif_save(struct map_session_data *sd) { nullpo_retr(-1, sd); if (char_fd < 0) return -1; pc_makesavestatus(sd); WFIFOW(char_fd, 0) = 0x2b01; WFIFOW(char_fd, 2) = sizeof(sd->status) + 12; WFIFOL(char_fd, 4) = sd->bl.id; WFIFOL(char_fd, 8) = sd->char_id; memcpy(WFIFOP(char_fd, 12), &sd->status, sizeof(sd->status)); WFIFOSET(char_fd, WFIFOW(char_fd, 2)); //For data sync if (sd->state.storage_open) storage_storage_save(sd->status.account_id, 0); return 0; } /*========================================== * *------------------------------------------ */ static int chrif_connect(int fd) { WFIFOW(fd, 0) = 0x2af8; memcpy(WFIFOP(fd, 2), userid, 24); memcpy(WFIFOP(fd, 26), passwd, 24); WFIFOL(fd, 50) = 0; WFIFOL(fd, 54) = clif_getip().s_addr; WFIFOW(fd, 58) = clif_getport(); // [Valaris] thanks to fov WFIFOSET(fd, 60); return 0; } /*========================================== * マップ送信 *------------------------------------------ */ static int chrif_sendmap(int fd) { int i; WFIFOW(fd, 0) = 0x2afa; for (i = 0; i < map_num; i++) if (map[i].alias[0] != '\0') // [MouseJstr] map aliasing memcpy(WFIFOP(fd, 4 + i * 16), map[i].alias, 16); else memcpy(WFIFOP(fd, 4 + i * 16), map[i].name, 16); WFIFOW(fd, 2) = 4 + i * 16; WFIFOSET(fd, WFIFOW(fd, 2)); return 0; } /*========================================== * マップ受信 *------------------------------------------ */ static int chrif_recvmap(int fd) { int i, j, port; if (chrif_state < 2) // まだ準備中 return -1; struct in_addr ip; ip.s_addr = RFIFOL(fd, 4); port = RFIFOW(fd, 8); for (i = 10, j = 0; i < RFIFOW(fd, 2); i += 16, j++) { map_setipport((const char *)RFIFOP(fd, i), ip, port); // if (battle_config.etc_log) // printf("recv map %d %s\n", j, RFIFOP(fd,i)); } if (battle_config.etc_log) printf("recv map on %s:%d (%d maps)\n", ip2str(ip), port, j); return 0; } /*========================================== * マップ鯖間移動のためのデータ準備要求 *------------------------------------------ */ int chrif_changemapserver(struct map_session_data *sd, char *name, int x, int y, struct in_addr ip, short port) { int i, s_ip; nullpo_retr(-1, sd); s_ip = 0; for (i = 0; i < fd_max; i++) if (session[i] && session[i]->session_data == sd) { s_ip = session[i]->client_addr.sin_addr.s_addr; break; } WFIFOW(char_fd, 0) = 0x2b05; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->login_id1; WFIFOL(char_fd, 10) = sd->login_id2; WFIFOL(char_fd, 14) = sd->status.char_id; memcpy(WFIFOP(char_fd, 18), name, 16); WFIFOW(char_fd, 34) = x; WFIFOW(char_fd, 36) = y; WFIFOL(char_fd, 38) = ip.s_addr; WFIFOL(char_fd, 42) = port; WFIFOB(char_fd, 44) = sd->status.sex; WFIFOL(char_fd, 45) = s_ip; WFIFOSET(char_fd, 49); return 0; } /*========================================== * マップ鯖間移動ack *------------------------------------------ */ static int chrif_changemapserverack(int fd) { struct map_session_data *sd = map_id2sd(RFIFOL(fd, 2)); if (sd == NULL || sd->status.char_id != RFIFOL(fd, 14)) return -1; if (RFIFOL(fd, 6) == 1) { if (battle_config.error_log) printf("map server change failed.\n"); pc_authfail(sd->fd); return 0; } clif_changemapserver(sd, (const char *)RFIFOP(fd, 18), RFIFOW(fd, 34), RFIFOW(fd, 36), in_addr{RFIFOL(fd, 38)}, RFIFOW(fd, 42)); return 0; } /*========================================== * *------------------------------------------ */ static int chrif_connectack(int fd) { if (RFIFOB(fd, 2)) { printf("Connected to char-server failed %d.\n", RFIFOB(fd, 2)); exit(1); } printf("Connected to char-server (connection #%d).\n", fd); chrif_state = 1; chrif_sendmap(fd); printf("chrif: OnCharIfInit event done. (%d events)\n", npc_event_doall("OnCharIfInit")); printf("chrif: OnInterIfInit event done. (%d events)\n", npc_event_doall("OnInterIfInit")); // Run Event [AgitInit] // printf("NPC_Event:[OnAgitInit] do (%d) events (Agit Initialize).\n", npc_event_doall("OnAgitInit")); return 0; } /*========================================== * *------------------------------------------ */ static int chrif_sendmapack(int fd) { if (RFIFOB(fd, 2)) { printf("chrif : send map list to char server failed %d\n", RFIFOB(fd, 2)); exit(1); } memcpy(wisp_server_name, RFIFOP(fd, 3), 24); chrif_state = 2; return 0; } /*========================================== * *------------------------------------------ */ int chrif_authreq(struct map_session_data *sd) { int i; nullpo_retr(-1, sd); if (!sd || !char_fd || !sd->bl.id || !sd->login_id1) return -1; for (i = 0; i < fd_max; i++) if (session[i] && session[i]->session_data == sd) { WFIFOW(char_fd, 0) = 0x2afc; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->char_id; WFIFOL(char_fd, 10) = sd->login_id1; WFIFOL(char_fd, 14) = sd->login_id2; WFIFOL(char_fd, 18) = session[i]->client_addr.sin_addr.s_addr; WFIFOSET(char_fd, 22); break; } return 0; } /*========================================== * *------------------------------------------ */ int chrif_charselectreq(struct map_session_data *sd) { int i, s_ip; nullpo_retr(-1, sd); if (!sd || !char_fd || !sd->bl.id || !sd->login_id1) return -1; s_ip = 0; for (i = 0; i < fd_max; i++) if (session[i] && session[i]->session_data == sd) { s_ip = session[i]->client_addr.sin_addr.s_addr; break; } WFIFOW(char_fd, 0) = 0x2b02; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->login_id1; WFIFOL(char_fd, 10) = sd->login_id2; WFIFOL(char_fd, 14) = s_ip; WFIFOSET(char_fd, 18); return 0; } /*========================================== * キャラ名問い合わせ *------------------------------------------ */ int chrif_searchcharid(int char_id) { if (!char_id) return -1; WFIFOW(char_fd, 0) = 0x2b08; WFIFOL(char_fd, 2) = char_id; WFIFOSET(char_fd, 6); return 0; } /*========================================== * GMに変化要求 *------------------------------------------ */ int chrif_changegm(int id, const char *pass, int len) { if (battle_config.etc_log) printf("chrif_changegm: account: %d, password: '%s'.\n", id, pass); WFIFOW(char_fd, 0) = 0x2b0a; WFIFOW(char_fd, 2) = len + 8; WFIFOL(char_fd, 4) = id; memcpy(WFIFOP(char_fd, 8), pass, len); WFIFOSET(char_fd, len + 8); return 0; } /*========================================== * Change Email *------------------------------------------ */ int chrif_changeemail(int id, const char *actual_email, const char *new_email) { if (battle_config.etc_log) printf("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", id, actual_email, new_email); WFIFOW(char_fd, 0) = 0x2b0c; WFIFOL(char_fd, 2) = id; memcpy(WFIFOP(char_fd, 6), actual_email, 40); memcpy(WFIFOP(char_fd, 46), new_email, 40); WFIFOSET(char_fd, 86); return 0; } /*========================================== * Send message to char-server with a character name to do some operations (by Yor) * Used to ask Char-server about a character name to have the account number to modify account file in login-server. * type of operation: * 1: block * 2: ban * 3: unblock * 4: unban * 5: changesex *------------------------------------------ */ int chrif_char_ask_name(int id, char *character_name, short operation_type, int year, int month, int day, int hour, int minute, int second) { WFIFOW(char_fd, 0) = 0x2b0e; WFIFOL(char_fd, 2) = id; // account_id of who ask (for answer) -1 if nobody memcpy(WFIFOP(char_fd, 6), character_name, 24); WFIFOW(char_fd, 30) = operation_type; // type of operation if (operation_type == 2) { WFIFOW(char_fd, 32) = year; WFIFOW(char_fd, 34) = month; WFIFOW(char_fd, 36) = day; WFIFOW(char_fd, 38) = hour; WFIFOW(char_fd, 40) = minute; WFIFOW(char_fd, 42) = second; } printf("chrif : sended 0x2b0e\n"); WFIFOSET(char_fd, 44); return 0; } /*========================================== * Answer after a request about a character name to do some operations (by Yor) * Used to answer of chrif_char_ask_name. * type of operation: * 1: block * 2: ban * 3: unblock * 4: unban * 5: changesex * type of answer: * 0: login-server resquest done * 1: player not found * 2: gm level too low * 3: login-server offline *------------------------------------------ */ static int chrif_char_ask_name_answer(int fd) { int acc; struct map_session_data *sd; char output[256]; char player_name[24]; acc = RFIFOL(fd, 2); // account_id of who has asked (-1 if nobody) memcpy(player_name, RFIFOP(fd, 6), sizeof(player_name)); player_name[sizeof(player_name) - 1] = '\0'; sd = map_id2sd(acc); if (acc >= 0 && sd != NULL) { if (RFIFOW(fd, 32) == 1) // player not found sprintf(output, "The player '%s' doesn't exist.", player_name); else { switch (RFIFOW(fd, 30)) { case 1: // block switch (RFIFOW(fd, 32)) { case 0: // login-server resquest done sprintf(output, "Login-server has been asked to block the player '%s'.", player_name); break; //case 1: // player not found case 2: // gm level too low sprintf(output, "Your GM level don't authorise you to block the player '%s'.", player_name); break; case 3: // login-server offline sprintf(output, "Login-server is offline. Impossible to block the the player '%s'.", player_name); break; } break; case 2: // ban switch (RFIFOW(fd, 32)) { case 0: // login-server resquest done sprintf(output, "Login-server has been asked to ban the player '%s'.", player_name); break; //case 1: // player not found case 2: // gm level too low sprintf(output, "Your GM level don't authorise you to ban the player '%s'.", player_name); break; case 3: // login-server offline sprintf(output, "Login-server is offline. Impossible to ban the the player '%s'.", player_name); break; } break; case 3: // unblock switch (RFIFOW(fd, 32)) { case 0: // login-server resquest done sprintf(output, "Login-server has been asked to unblock the player '%s'.", player_name); break; //case 1: // player not found case 2: // gm level too low sprintf(output, "Your GM level don't authorise you to unblock the player '%s'.", player_name); break; case 3: // login-server offline sprintf(output, "Login-server is offline. Impossible to unblock the the player '%s'.", player_name); break; } break; case 4: // unban switch (RFIFOW(fd, 32)) { case 0: // login-server resquest done sprintf(output, "Login-server has been asked to unban the player '%s'.", player_name); break; //case 1: // player not found case 2: // gm level too low sprintf(output, "Your GM level don't authorise you to unban the player '%s'.", player_name); break; case 3: // login-server offline sprintf(output, "Login-server is offline. Impossible to unban the the player '%s'.", player_name); break; } break; case 5: // changesex switch (RFIFOW(fd, 32)) { case 0: // login-server resquest done sprintf(output, "Login-server has been asked to change the sex of the player '%s'.", player_name); break; //case 1: // player not found case 2: // gm level too low sprintf(output, "Your GM level don't authorise you to change the sex of the player '%s'.", player_name); break; case 3: // login-server offline sprintf(output, "Login-server is offline. Impossible to change the sex of the the player '%s'.", player_name); break; } break; } } if (output[0] != '\0') { output[sizeof(output) - 1] = '\0'; clif_displaymessage(sd->fd, output); } } else printf("chrif_char_ask_name_answer failed - player not online.\n"); return 0; } /*========================================== * End of GM change(@GM) (modified by Yor) *------------------------------------------ */ static int chrif_changedgm(int fd) { int acc, level; struct map_session_data *sd = NULL; acc = RFIFOL(fd, 2); level = RFIFOL(fd, 6); sd = map_id2sd(acc); if (battle_config.etc_log) printf("chrif_changedgm: account: %d, GM level 0 -> %d.\n", acc, level); if (sd != NULL) { if (level > 0) clif_displaymessage(sd->fd, "GM modification success."); else clif_displaymessage(sd->fd, "Failure of GM modification."); } return 0; } /*========================================== * 性別変化終了 (modified by Yor) *------------------------------------------ */ static int chrif_changedsex(int fd) { int acc, sex, i; struct map_session_data *sd; struct pc_base_job s_class; acc = RFIFOL(fd, 2); sex = RFIFOL(fd, 6); if (battle_config.etc_log) printf("chrif_changedsex %d.\n", acc); sd = map_id2sd(acc); if (acc > 0) { if (sd != NULL && sd->status.sex != sex) { s_class = pc_calc_base_job(sd->status.pc_class); if (sd->status.sex == 0) { sd->status.sex = 1; sd->sex = 1; } else if (sd->status.sex == 1) { sd->status.sex = 0; sd->sex = 0; } // to avoid any problem with equipment and invalid sex, equipment is unequiped. for (i = 0; i < MAX_INVENTORY; i++) { if (sd->status.inventory[i].nameid && sd->status.inventory[i].equip) pc_unequipitem((struct map_session_data *) sd, i, 0); } // reset skill of some job if (s_class.job == 19 || s_class.job == 4020 || s_class.job == 4042 || s_class.job == 20 || s_class.job == 4021 || s_class.job == 4043) { clif_updatestatus(sd, SP_SKILLPOINT); // change job if necessary if (s_class.job == 20 || s_class.job == 4021 || s_class.job == 4043) sd->status.pc_class -= 1; else if (s_class.job == 19 || s_class.job == 4020 || s_class.job == 4042) sd->status.pc_class += 1; } // save character chrif_save(sd); sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it) clif_displaymessage(sd->fd, "Your sex has been changed (need disconexion by the server)..."); clif_setwaitclose(sd->fd); // forced to disconnect for the change } } else { if (sd != NULL) { printf("chrif_changedsex failed.\n"); } } return 0; } /*========================================== * アカウント変数保存要求 *------------------------------------------ */ int chrif_saveaccountreg2(struct map_session_data *sd) { int p, j; nullpo_retr(-1, sd); p = 8; for (j = 0; j < sd->status.account_reg2_num; j++) { struct global_reg *reg = &sd->status.account_reg2[j]; if (reg->str[0] && reg->value != 0) { memcpy(WFIFOP(char_fd, p), reg->str, 32); WFIFOL(char_fd, p + 32) = reg->value; p += 36; } } WFIFOW(char_fd, 0) = 0x2b10; WFIFOW(char_fd, 2) = p; WFIFOL(char_fd, 4) = sd->bl.id; WFIFOSET(char_fd, p); return 0; } /*========================================== * アカウント変数通知 *------------------------------------------ */ static int chrif_accountreg2(int fd) { int j, p; struct map_session_data *sd; if ((sd = map_id2sd(RFIFOL(fd, 4))) == NULL) return 1; for (p = 8, j = 0; p < RFIFOW(fd, 2) && j < ACCOUNT_REG2_NUM; p += 36, j++) { memcpy(sd->status.account_reg2[j].str, RFIFOP(fd, p), 32); sd->status.account_reg2[j].value = RFIFOL(fd, p + 32); } sd->status.account_reg2_num = j; // printf("chrif: accountreg2\n"); return 0; } /*========================================== * Divorce request from char server * triggered on account deletion or as an * ack from a map-server divorce request *------------------------------------------ */ static int chrif_divorce(int char_id, int partner_id) { struct map_session_data *sd = NULL; if (!char_id || !partner_id) return 0; sd = map_nick2sd(map_charid2nick(char_id)); if (sd && sd->status.partner_id == partner_id) { sd->status.partner_id = 0; if (sd->npc_flags.divorce) { sd->npc_flags.divorce = 0; map_scriptcont(sd, sd->npc_id); } } nullpo_retr(0, sd = map_nick2sd(map_charid2nick(partner_id))); if (sd->status.partner_id == char_id) sd->status.partner_id = 0; return 0; } /*========================================== * Tell character server someone is divorced * Needed to divorce when partner is not connected to map server *------------------------------------- */ int chrif_send_divorce(int char_id) { if (char_fd < 0) return -1; WFIFOW(char_fd, 0) = 0x2b16; WFIFOL(char_fd, 2) = char_id; WFIFOSET(char_fd, 6); return 0; } /*========================================== * Disconnection of a player (account has been deleted in login-server) by [Yor] *------------------------------------------ */ static int chrif_accountdeletion(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd, 2); if (battle_config.etc_log) printf("chrif_accountdeletion %d.\n", acc); sd = map_id2sd(acc); if (acc > 0) { if (sd != NULL) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters clif_displaymessage(sd->fd, "Your account has been deleted (disconnection)..."); clif_setwaitclose(sd->fd); // forced to disconnect for the change } } else { if (sd != NULL) printf("chrif_accountdeletion failed - player not online.\n"); } return 0; } /*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------ */ static int chrif_accountban(int fd) { int acc; struct map_session_data *sd; acc = RFIFOL(fd, 2); if (battle_config.etc_log) printf("chrif_accountban %d.\n", acc); sd = map_id2sd(acc); if (acc > 0) { if (sd != NULL) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (RFIFOB(fd, 6) == 0) { // 0: change of statut, 1: ban switch (RFIFOL(fd, 7)) { // status or final date of a banishment case 1: // 0 = Unregistered ID clif_displaymessage(sd->fd, "Your account has 'Unregistered'."); break; case 2: // 1 = Incorrect Password clif_displaymessage(sd->fd, "Your account has an 'Incorrect Password'..."); break; case 3: // 2 = This ID is expired clif_displaymessage(sd->fd, "Your account has expired."); break; case 4: // 3 = Rejected from Server clif_displaymessage(sd->fd, "Your account has been rejected from server."); break; case 5: // 4 = You have been blocked by the GM Team clif_displaymessage(sd->fd, "Your account has been blocked by the GM Team."); break; case 6: // 5 = Your Game's EXE file is not the latest version clif_displaymessage(sd->fd, "Your Game's EXE file is not the latest version."); break; case 7: // 6 = Your are Prohibited to log in until %s clif_displaymessage(sd->fd, "Your account has been prohibited to log in."); break; case 8: // 7 = Server is jammed due to over populated clif_displaymessage(sd->fd, "Server is jammed due to over populated."); break; case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) clif_displaymessage(sd->fd, "Your account has not more authorised."); break; case 100: // 99 = This ID has been totally erased clif_displaymessage(sd->fd, "Your account has been totally erased."); break; default: clif_displaymessage(sd->fd, "Your account has not more authorised."); break; } } else if (RFIFOB(fd, 6) == 1) { // 0: change of statut, 1: ban time_t timestamp; char tmpstr[2048]; timestamp = (time_t) RFIFOL(fd, 7); // status or final date of a banishment strcpy(tmpstr, "Your account has been banished until "); strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", gmtime(×tamp)); clif_displaymessage(sd->fd, tmpstr); } clif_setwaitclose(sd->fd); // forced to disconnect for the change } } else { if (sd != NULL) printf("chrif_accountban failed - player not online.\n"); } return 0; } /*========================================== * Receiving GM accounts and their levels from char-server by [Yor] *------------------------------------------ */ static int chrif_recvgmaccounts(int fd) { printf("From login-server: receiving of %d GM accounts information.\n", pc_read_gm_account(fd)); return 0; } /*========================================== * Request to reload GM accounts and their levels: send to char-server by [Yor] *------------------------------------------ */ int chrif_reloadGMdb(void) { WFIFOW(char_fd, 0) = 0x2af7; WFIFOSET(char_fd, 2); return 0; } /*========================================== * Send rates and motd to char server [Wizputer] *------------------------------------------ */ int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate) { char buf[256]; FILE *fp; int i; WFIFOW(char_fd, 0) = 0x2b16; WFIFOW(char_fd, 2) = base_rate; WFIFOW(char_fd, 4) = job_rate; WFIFOW(char_fd, 6) = drop_rate; if ((fp = fopen_(motd_txt, "r")) != NULL) { if (fgets(buf, 250, fp) != NULL) { for (i = 0; buf[i]; i++) { if (buf[i] == '\r' || buf[i] == '\n') { buf[i] = 0; break; } } WFIFOW(char_fd, 8) = sizeof(buf) + 10; memcpy(WFIFOP(char_fd, 10), buf, sizeof(buf)); } fclose_(fp); } else { WFIFOW(char_fd, 8) = sizeof(buf) + 10; memcpy(WFIFOP(char_fd, 10), buf, sizeof(buf)); } WFIFOSET(char_fd, WFIFOW(char_fd, 8)); return 0; } /*========================================= * Tell char-server charcter disconnected [Wizputer] *----------------------------------------- */ int chrif_char_offline(struct map_session_data *sd) { if (char_fd < 0) return -1; WFIFOW(char_fd, 0) = 0x2b17; WFIFOL(char_fd, 2) = sd->status.char_id; WFIFOSET(char_fd, 6); return 0; } /*======================================== * Map item IDs *---------------------------------------- */ static void ladmin_itemfrob_fix_item(int source, int dest, struct item *item) { if (item && item->nameid == source) { item->nameid = dest; item->equip = 0; } } static void ladmin_itemfrob_c2(struct block_list *bl, int source_id, int dest_id) { #define IFIX(v) if (v == source_id) {v = dest_id; } #define FIX(item) ladmin_itemfrob_fix_item(source_id, dest_id, &item) if (!bl) return; switch (bl->type) { case BL_PC: { struct map_session_data *pc = (struct map_session_data *) bl; struct storage *stor = account2storage2(pc->status.account_id); int j; for (j = 0; j < MAX_INVENTORY; j++) IFIX(pc->status.inventory[j].nameid); for (j = 0; j < MAX_CART; j++) IFIX(pc->status.cart[j].nameid); IFIX(pc->status.weapon); IFIX(pc->status.shield); IFIX(pc->status.head_top); IFIX(pc->status.head_mid); IFIX(pc->status.head_bottom); if (stor) for (j = 0; j < stor->storage_amount; j++) FIX(stor->storage_[j]); for (j = 0; j < MAX_INVENTORY; j++) { struct item_data *item = pc->inventory_data[j]; if (item && item->nameid == source_id) { item->nameid = dest_id; if (item->equip) pc_unequipitem(pc, j, 0); item->nameid = dest_id; } } break; } case BL_MOB: { struct mob_data *mob = (struct mob_data *) bl; int i; for (i = 0; i < mob->lootitem_count; i++) FIX(mob->lootitem[i]); break; } case BL_ITEM: { struct flooritem_data *item = (struct flooritem_data *) bl; FIX(item->item_data); break; } } #undef FIX #undef IFIX } static void ladmin_itemfrob_c(struct block_list *bl, va_list va_args) { int source_id = va_arg(va_args, int); int dest_id = va_arg(va_args, int); ladmin_itemfrob_c2(bl, source_id, dest_id); } static void ladmin_itemfrob(int fd) { int source_id = RFIFOL(fd, 2); int dest_id = RFIFOL(fd, 6); struct block_list *bl = (struct block_list *) map_get_first_session(); // flooritems map_foreachobject(ladmin_itemfrob_c, 0 /* any object */ , source_id, dest_id); // player characters (and, hopefully, mobs) while (bl->next) { ladmin_itemfrob_c2(bl, source_id, dest_id); bl = bl->next; } } /*========================================== * *------------------------------------------ */ static void chrif_parse(int fd) { int packet_len, cmd; // only char-server can have an access to here. // so, if it isn't the char-server, we disconnect the session (fd != char_fd). if (fd != char_fd || session[fd]->eof) { if (fd == char_fd) { printf("Map-server can't connect to char-server (connection #%d).\n", fd); char_fd = -1; } close(fd); delete_session(fd); return; } while (RFIFOREST(fd) >= 2) { cmd = RFIFOW(fd, 0); if (cmd < 0x2af8 || cmd >= 0x2af8 + (sizeof(packet_len_table) / sizeof(packet_len_table[0])) || packet_len_table[cmd - 0x2af8] == 0) { int r = intif_parse(fd); // intifに渡す if (r == 1) continue; // intifで処理した if (r == 2) return; // intifで処理したが、データが足りない session[fd]->eof = 1; return; } packet_len = packet_len_table[cmd - 0x2af8]; if (packet_len == -1) { if (RFIFOREST(fd) < 4) return; packet_len = RFIFOW(fd, 2); } if (RFIFOREST(fd) < packet_len) return; switch (cmd) { case 0x2af9: chrif_connectack(fd); break; case 0x2afa: ladmin_itemfrob(fd); break; case 0x2afb: chrif_sendmapack(fd); break; case 0x2afd: pc_authok(RFIFOL(fd, 4), RFIFOL(fd, 8), (time_t) RFIFOL(fd, 12), RFIFOW(fd, 16), (struct mmo_charstatus *) RFIFOP(fd, 18)); break; case 0x2afe: pc_authfail(RFIFOL(fd, 2)); break; case 0x2b00: map_setusers(RFIFOL(fd, 2)); break; case 0x2b03: clif_charselectok(RFIFOL(fd, 2)); break; case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(fd); break; case 0x2b09: map_addchariddb(RFIFOL(fd, 2), (const char *)RFIFOP(fd, 6)); break; case 0x2b0b: chrif_changedgm(fd); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(fd); break; case 0x2b11: chrif_accountreg2(fd); break; case 0x2b12: chrif_divorce(RFIFOL(fd, 2), RFIFOL(fd, 6)); break; case 0x2b13: chrif_accountdeletion(fd); break; case 0x2b14: chrif_accountban(fd); break; case 0x2b15: chrif_recvgmaccounts(fd); break; default: if (battle_config.error_log) printf("chrif_parse : unknown packet %d %d\n", fd, RFIFOW(fd, 0)); session[fd]->eof = 1; return; } RFIFOSKIP(fd, packet_len); } } /*========================================== * timer関数 * 今このmap鯖に繋がっているクライアント人数をchar鯖へ送る *------------------------------------------ */ static void send_users_tochar(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) { int users = 0, i; struct map_session_data *sd; if (char_fd <= 0 || session[char_fd] == NULL) return; WFIFOW(char_fd, 0) = 0x2aff; for (i = 0; i < fd_max; i++) { if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) && sd->state.auth && !((battle_config.hide_GM_session || sd->state.shroud_active || (sd->status.option & OPTION_HIDE)) && pc_isGM(sd))) { WFIFOL(char_fd, 6 + 4 * users) = sd->status.char_id; users++; } } WFIFOW(char_fd, 2) = 6 + 4 * users; WFIFOW(char_fd, 4) = users; WFIFOSET(char_fd, 6 + 4 * users); } /*========================================== * timer関数 * char鯖との接続を確認し、もし切れていたら再度接続する *------------------------------------------ */ static void check_connect_char_server(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) { if (char_fd <= 0 || session[char_fd] == NULL) { printf("Attempt to connect to char-server...\n"); chrif_state = 0; if ((char_fd = make_connection(char_ip, char_port)) < 0) return; session[char_fd]->func_parse = chrif_parse; realloc_fifo(char_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); chrif_connect(char_fd); } } /*========================================== * *------------------------------------------ */ int do_init_chrif (void) { // add_timer_func_list (check_connect_char_server, "check_connect_char_server"); // add_timer_func_list (send_users_tochar, "send_users_tochar"); add_timer_interval(gettick() + 1000, check_connect_char_server, 0, 0, 10 * 1000); add_timer_interval(gettick() + 1000, send_users_tochar, 0, 0, 5 * 1000); return 0; }