// パーティが追加された int party_member_added(PartyId party_id, AccountId account_id, int flag) { dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)), sd2; PartyPair p = party_search(party_id); if (sd == nullptr) { if (flag == 0) { if (battle_config.error_log) PRINTF("party: member added error %d is not online\n"_fmt, account_id); intif_party_leave(party_id, account_id); // キャラ側に登録できなかったため脱退要求を出す } return 0; } sd2 = map_id2sd(account_to_block(sd->party_invite_account)); sd->party_invite = PartyId(); sd->party_invite_account = AccountId(); if (!p) { PRINTF("party_member_added: party %d not found.\n"_fmt, party_id); intif_party_leave(party_id, account_id); return 0; } if (flag == 1) { // 失敗 if (sd2 != nullptr) clif_party_inviteack(sd2, sd->status_key.name, 0); return 0; } // 成功 sd->party_sended = 0; sd->status.party_id = party_id; if (sd2 != nullptr) clif_party_inviteack(sd2, sd->status_key.name, 2); // いちおう競合確認 party_check_conflict(sd); party_send_xy_clear(p); return 0; }
/* Relay the result of a party creation request. */ void party_created(AccountId account_id, int fail, PartyId party_id, PartyName name) { dumb_ptr<map_session_data> sd; sd = map_id2sd(account_to_block(account_id)); nullpo_retv(sd); /* The party name is valid and not already taken. */ if (!fail) { sd->status.party_id = party_id; PartyPair p = party_search(party_id); if (p) { PRINTF("party_created(): ID already exists!\n"_fmt); exit(1); } p.party_most = party_db.init(party_id); p.party_id = party_id; p->name = name; /* The party was created successfully. */ clif_party_created(sd, 0); } else clif_party_created(sd, 1); }
/* Process response to party invitation. */ int party_reply_invite(dumb_ptr<map_session_data> sd, AccountId account_id, int flag) { nullpo_retz(sd); /* There is no pending invitation. */ if (!sd->party_invite || !sd->party_invite_account) return 0; /* * Only one invitation can be pending, so these have to be the same. Since * the client continues to send the wrong ID, and it's already managed on * this side of things, the sent ID is being ignored. */ account_id = sd->party_invite_account; /* The invitation was accepted. */ if (flag == 1) intif_party_addmember(sd->party_invite, sd->status_key.account_id); /* The invitation was rejected. */ else { /* This is the player who sent the invitation. */ dumb_ptr<map_session_data> tsd = nullptr; sd->party_invite = PartyId(); sd->party_invite_account = AccountId(); if ((tsd = map_id2sd(account_to_block(account_id)))) clif_party_inviteack(tsd, sd->status_key.name, 1); } return 0; }
/*========================================== * マップ鯖間移動ack *------------------------------------------ */ static int chrif_changemapserverack(Session *, const Packet_Fixed<0x2b06>& fixed) { dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(fixed.account_id)); if (sd == nullptr || sd->status_key.char_id != fixed.char_id) return -1; // I am fairly certain that this is not possible if (fixed.error == 1) { if (battle_config.error_log) PRINTF("map server change failed.\n"_fmt); pc_authfail(sd->status_key.account_id); return 0; } MapName mapname = fixed.map_name; uint16_t x = fixed.x; uint16_t y = fixed.y; IP4Address ip = fixed.map_ip; uint16_t port = fixed.map_port; clif_changemapserver(sd, mapname, x, y, ip, port); return 0; }
/*========================================== * アイテム追加完了(ok押し) *------------------------------------------ */ void trade_tradeok(dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> target_sd; int trade_i; nullpo_retv(sd); for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { IOff2 index = sd->deal_item_index[trade_i]; if (!index.ok()) continue; if (sd->deal_item_amount[trade_i] > sd->status.inventory[index.unshift()].amount || sd->deal_item_amount[trade_i] < 0) { trade_tradecancel(sd); return; } } if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { sd->deal_locked = 1; clif_tradeitemok(sd, IOff2::from(0), 0, 0); clif_tradedeal_lock(sd, 0); clif_tradedeal_lock(target_sd, 1); } }
/*========================================== * 取引要請 *------------------------------------------ */ void trade_tradeack(dumb_ptr<map_session_data> sd, int type) { dumb_ptr<map_session_data> target_sd; nullpo_retv(sd); if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { clif_tradestart(target_sd, type); clif_tradestart(sd, type); if (type == 4) { // Cancel sd->deal_locked = 0; sd->trade_partner = AccountId(); target_sd->deal_locked = 0; target_sd->trade_partner = AccountId(); } if (sd->npc_id) npc_event_dequeue(sd); if (target_sd->npc_id) npc_event_dequeue(target_sd); //close STORAGE window if it's open. It protects from spooffing packets [Lupus] if (sd->state.storage_open) storage_storageclose(sd); } }
/*========================================== * Disconnection of a player (account has been deleted in login-server) by [Yor] *------------------------------------------ */ static int chrif_accountdeletion(Session *, const Packet_Fixed<0x2b13>& fixed) { dumb_ptr<map_session_data> sd; AccountId acc = fixed.account_id; if (battle_config.etc_log) PRINTF("chrif_accountdeletion %d.\n"_fmt, acc); sd = map_id2sd(account_to_block(acc)); if (acc) { if (sd != nullptr) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters clif_displaymessage(sd->sess, "Your account has been deleted (disconnection)..."_s); clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { if (sd != nullptr) PRINTF("chrif_accountdeletion failed - player not online.\n"_fmt); } return 0; }
/*========================================== * 取引キャンセル *------------------------------------------ */ void trade_tradecancel(dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> target_sd; int trade_i; nullpo_retv(sd); if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { //give items back (only virtual) if (sd->deal_item_amount[trade_i] != 0) { assert (sd->deal_item_index[trade_i].ok()); clif_additem(sd, sd->deal_item_index[trade_i].unshift(), sd->deal_item_amount[trade_i], PickupFail::OKAY); sd->deal_item_index[trade_i] = IOff2::from(0); sd->deal_item_amount[trade_i] = 0; } if (target_sd->deal_item_amount[trade_i] != 0) { assert (target_sd->deal_item_index[trade_i].ok()); clif_additem(target_sd, target_sd->deal_item_index[trade_i].unshift(), target_sd->deal_item_amount[trade_i], PickupFail::OKAY); target_sd->deal_item_index[trade_i] = IOff2::from(0); target_sd->deal_item_amount[trade_i] = 0; } } if (sd->deal_zeny) { sd->deal_zeny = 0; clif_updatestatus(sd, SP::ZENY); } if (target_sd->deal_zeny) { clif_updatestatus(target_sd, SP::ZENY); target_sd->deal_zeny = 0; } sd->deal_locked = 0; sd->trade_partner = AccountId(); target_sd->deal_locked = 0; target_sd->trade_partner = AccountId(); clif_tradecancelled(sd); clif_tradecancelled(target_sd); } }
// パーティの設定変更通知 int party_optionchanged(PartyId party_id, AccountId account_id, int exp, int item, int flag) { PartyPair p; dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)); if (!(p = party_search(party_id))) return 0; if (!(flag & 0x01)) p->exp = exp; if (!(flag & 0x10)) p->item = item; clif_party_option(p, sd, flag); return 0; }
// アカウント変数通知 static int intif_parse_AccountReg(Session *, const Packet_Head<0x3804>& head, const std::vector<Packet_Repeat<0x3804>>& repeat) { dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(head.account_id)); if (sd == nullptr) return 1; size_t jlim = std::min(ACCOUNT_REG_NUM, repeat.size()); for (size_t j = 0; j < jlim; j++) { sd->status.account_reg[j].str = repeat[j].name; sd->status.account_reg[j].value = repeat[j].value; } sd->status.account_reg_num = jlim; return 0; }
// This is called when a char's zeny is changed // This helps prevent money duplication and other problems // [Jaxad0127] void trade_verifyzeny(dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> target_sd; nullpo_retv(sd); if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { if (sd->deal_zeny > sd->status.zeny) { if (sd->deal_locked < 1) trade_tradeadditem(sd, IOff2::from(0), sd->status.zeny); // Fix money ammount else trade_tradecancel(sd); // Or cancel the trade if we can't fix it } } }
// パーティ追加要求 void intif_party_addmember(PartyId party_id, AccountId account_id) { if (!char_session) return; dumb_ptr<map_session_data> sd; sd = map_id2sd(account_to_block(account_id)); if (sd != nullptr) { Packet_Fixed<0x3022> fixed_22; fixed_22.party_id = party_id; fixed_22.account_id = account_id; fixed_22.char_name = sd->status_key.name; fixed_22.map_name = sd->bl_m->name_; fixed_22.level = sd->status.base_level; send_fpacket<0x3022, 52>(char_session, fixed_22); } }
/*========================================== * End of GM change(@GM) (modified by Yor) *------------------------------------------ */ static void chrif_changedgm(Session *, const Packet_Fixed<0x2b0b>& fixed) { AccountId acc = fixed.account_id; GmLevel level = fixed.gm_level; dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc)); if (battle_config.etc_log) PRINTF("chrif_changedgm: account: %d, GM level 0 -> %d.\n"_fmt, acc, level); if (sd != nullptr) { if (level) clif_displaymessage(sd->sess, "GM modification success."_s); else clif_displaymessage(sd->sess, "Failure of GM modification."_s); } }
/*========================================== * 性別変化終了 (modified by Yor) *------------------------------------------ */ static void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) { dumb_ptr<map_session_data> sd; AccountId acc = fixed.account_id; SEX sex = fixed.sex; if (battle_config.etc_log) PRINTF("chrif_changedsex %d.\n"_fmt, acc); sd = map_id2sd(account_to_block(acc)); if (acc) { if (sd != nullptr && sd->status.sex != sex) { if (sd->status.sex == SEX::MALE) sd->sex = sd->status.sex = SEX::FEMALE; else if (sd->status.sex == SEX::FEMALE) sd->sex = sd->status.sex = SEX::MALE; // to avoid any problem with equipment and invalid sex, equipment is unequiped. for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid && bool(sd->status.inventory[i].equip)) pc_unequipitem(sd, i, CalcStatus::NOW); } // 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->sess, "Your sex has been changed (need disconexion by the server)..."_s); clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { if (sd != nullptr) { PRINTF("chrif_changedsex failed.\n"_fmt); } } }
// パーティメンバの移動通知 void party_recv_movemap(PartyId party_id, AccountId account_id, MapName mapname, int online, int lv) { PartyPair p; int i; if (!(p = party_search(party_id))) return; for (i = 0; i < MAX_PARTY; i++) { PartyMember *m = &p->member[i]; if (m == nullptr) { PRINTF("party_recv_movemap nullpo?\n"_fmt); return; } if (m->account_id == account_id) { m->map = mapname; m->online = online; m->lv = lv; break; } } if (i == MAX_PARTY) { if (battle_config.error_log) PRINTF("party: not found member %d on %d[%s]"_fmt, account_id, party_id, p->name); return; } for (i = 0; i < MAX_PARTY; i++) { // sd再設定 dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(p->member[i].account_id)); p->member[i].sd = (sd != nullptr && sd->status.party_id == p.party_id) ? sd.operator->() : nullptr; } party_send_xy_clear(p); // 座標再通知要請 clif_party_info(p, nullptr); }
// 倉庫データ受信 static int intif_parse_LoadStorage(Session *, const Packet_Payload<0x3810>& payload) { dumb_ptr<map_session_data> sd; sd = map_id2sd(account_to_block(payload.account_id)); if (sd == nullptr) { if (battle_config.error_log) PRINTF("intif_parse_LoadStorage: user not found %d\n"_fmt, payload.account_id); return 1; } P<Storage> stor = account2storage(payload.account_id); if (stor->storage_status == 1) { // Already open.. lets ignore this update if (battle_config.error_log) PRINTF("intif_parse_LoadStorage: storage received for a client already open (User %d:%d)\n"_fmt, sd->status_key.account_id, sd->status_key.char_id); return 1; } if (stor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] if (battle_config.error_log) PRINTF("intif_parse_LoadStorage: received storage for an already modified non-saved storage! (User %d:%d)\n"_fmt, sd->status_key.account_id, sd->status_key.char_id); return 1; } if (battle_config.save_log) PRINTF("intif_openstorage: %d\n"_fmt, payload.account_id); *stor = payload.storage; stor->dirty = 0; stor->storage_status = 1; sd->state.storage_open = 1; clif_storageitemlist(sd, stor); clif_storageequiplist(sd, stor); clif_updatestorageamount(sd, stor); return 0; }
// 情報所得 int party_recv_info(const PartyPair sp) { int i; nullpo_retz(sp); PartyPair p = party_search(sp.party_id); if (!p) { p.party_most = party_db.init(sp.party_id); // 最初のロードなのでユーザーのチェックを行う *p.party_most = *sp.party_most; party_check_member(p); } else *p.party_most = *sp.party_most; for (i = 0; i < MAX_PARTY; i++) { // sdの設定 dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(p->member[i].account_id)); p->member[i].sd = (sd != nullptr && sd->status.party_id == p.party_id) ? sd.operator->() : nullptr; } clif_party_info(p, nullptr); for (i = 0; i < MAX_PARTY; i++) { // 設定情報の送信 // dumb_ptr<map_session_data> sd = map_id2sd(p->member[i].account_id); dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(p->member[i].sd); if (sd != nullptr && sd->party_sended == 0) { clif_party_option(p, sd, 0x100); sd->party_sended = 1; } } return 0; }
// パーティメンバが脱退した int party_member_leaved(PartyId party_id, AccountId account_id, CharName name) { dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(account_id)); PartyPair p = party_search(party_id); if (p) { int i; for (i = 0; i < MAX_PARTY; i++) if (p->member[i].account_id == account_id) { clif_party_leaved(p, sd, account_id, name, 0x00); p->member[i].account_id = AccountId(); p->member[i].sd = nullptr; } } if (sd != nullptr && sd->status.party_id == party_id) { sd->status.party_id = PartyId(); sd->party_sended = 0; } return 0; }
/*========================================== * 性別変化終了 (modified by Yor) *------------------------------------------ */ static void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) { dumb_ptr<map_session_data> sd; AccountId acc = fixed.account_id; SEX sex = fixed.sex; if (battle_config.etc_log) PRINTF("chrif_changedsex %d.\n"_fmt, acc); sd = map_id2sd(account_to_block(acc)); if (acc) { if (sd != nullptr && sd->status.sex != sex) { sd->sex = sd->status.sex = sex; // to avoid any problem with equipment and invalid sex, equipment is unequiped. for (IOff0 i : IOff0::iter()) { if (sd->status.inventory[i].nameid && bool(sd->status.inventory[i].equip)) pc_unequipitem(sd, i, CalcStatus::LATER); } pc_calcstatus(sd, 0); // 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_fixpcpos(sd); // use clif_set0078_main_1d8 to send new sex to the client } } else { if (sd != nullptr) { PRINTF("chrif_changedsex failed.\n"_fmt); } } }
/*========================================== * 取引許諾(trade押し) *------------------------------------------ */ void trade_tradecommit(dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> target_sd; int trade_i; nullpo_retv(sd); if ((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) { MAP_LOG_PC(sd, " TRADECOMMIT WITH %d GIVE %d GET %d"_fmt, target_sd->status_key.char_id, sd->deal_zeny, target_sd->deal_zeny); if ((sd->deal_locked >= 1) && (target_sd->deal_locked >= 1)) { // both have pressed 'ok' if (sd->deal_locked < 2) { sd->deal_locked = 2; } // set locked to 2 if (target_sd->deal_locked == 2) { // the other one pressed 'trade' too if (sd->deal_zeny > sd->status.zeny) { sd->deal_zeny = 0; trade_tradecancel(sd); MAP_LOG_PC(sd, " TRADECANCEL"_fmt); return; } if (target_sd->deal_zeny > target_sd->status.zeny) { target_sd->deal_zeny = 0; trade_tradecancel(sd); MAP_LOG_PC(sd, " TRADECANCEL"_fmt); return; } sd->trade_partner = AccountId(); target_sd->trade_partner = AccountId(); for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { if (sd->deal_item_amount[trade_i] != 0) { assert (sd->deal_item_index[trade_i].ok()); IOff0 n = sd->deal_item_index[trade_i].unshift(); PickupFail flag = pc_additem(target_sd, &sd->status.inventory[n], sd->deal_item_amount[trade_i]); if (flag == PickupFail::OKAY) pc_delitem(sd, n, sd->deal_item_amount[trade_i], 1); else clif_additem(sd, n, sd->deal_item_amount[trade_i], PickupFail::OKAY); sd->deal_item_index[trade_i] = IOff2::from(0); sd->deal_item_amount[trade_i] = 0; } if (target_sd->deal_item_amount[trade_i] != 0) { assert (target_sd->deal_item_index[trade_i].ok()); IOff0 n = target_sd->deal_item_index[trade_i].unshift(); PickupFail flag = pc_additem(sd, &target_sd->status.inventory[n], target_sd->deal_item_amount[trade_i]); if (flag == PickupFail::OKAY) pc_delitem(target_sd, n, target_sd->deal_item_amount[trade_i], 1); else clif_additem(target_sd, n, target_sd->deal_item_amount[trade_i], PickupFail::OKAY); target_sd->deal_item_index[trade_i] = IOff2::from(0); target_sd->deal_item_amount[trade_i] = 0; } } if (sd->deal_zeny) { int deal = sd->deal_zeny; sd->deal_zeny = 0; sd->status.zeny -= deal; clif_updatestatus(sd, SP::ZENY); target_sd->status.zeny += deal; clif_updatestatus(target_sd, SP::ZENY); } if (target_sd->deal_zeny) { int deal = target_sd->deal_zeny; target_sd->deal_zeny = 0; target_sd->status.zeny -= deal; clif_updatestatus(target_sd, SP::ZENY); sd->status.zeny += deal; clif_updatestatus(sd, SP::ZENY); } sd->deal_locked = 0; target_sd->deal_locked = 0; clif_tradecompleted(sd, 0); clif_tradecompleted(target_sd, 0); MAP_LOG_PC(sd, " TRADEOK"_fmt); } } } }
/*========================================== * *------------------------------------------ */ static void chrif_parse(Session *s) { assert (s == char_session); RecvResult rv = RecvResult::Complete; uint16_t packet_id; while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { switch (packet_id) { case 0x2af9: { Packet_Fixed<0x2af9> fixed; rv = recv_fpacket<0x2af9, 3>(s, fixed); if (rv != RecvResult::Complete) break; chrif_connectack(s, fixed); break; } case 0x2afa: { Packet_Fixed<0x2afa> fixed; rv = recv_fpacket<0x2afa, 10>(s, fixed); if (rv != RecvResult::Complete) break; ladmin_itemfrob(s, fixed); break; } case 0x2afb: { Packet_Fixed<0x2afb> fixed; rv = recv_fpacket<0x2afb, 27>(s, fixed); if (rv != RecvResult::Complete) break; chrif_sendmapack(s, fixed); break; } case 0x2afd: { Packet_Payload<0x2afd> payload; rv = recv_ppacket<0x2afd>(s, payload); if (rv != RecvResult::Complete) break; AccountId id = payload.account_id; int login_id2 = payload.login_id2; TimeT connect_until_time = payload.connect_until; short tmw_version = payload.packet_tmw_version; CharKey st_key = payload.char_key; CharData st_data = payload.char_data; pc_authok(id, login_id2, connect_until_time, tmw_version, &st_key, &st_data); break; } case 0x2afe: { Packet_Fixed<0x2afe> fixed; rv = recv_fpacket<0x2afe, 6>(s, fixed); if (rv != RecvResult::Complete) break; pc_authfail(fixed.account_id); break; } case 0x2b00: { Packet_Fixed<0x2b00> fixed; rv = recv_fpacket<0x2b00, 6>(s, fixed); if (rv != RecvResult::Complete) break; map_setusers(fixed.users); break; } case 0x2b03: { Packet_Fixed<0x2b03> fixed; rv = recv_fpacket<0x2b03, 7>(s, fixed); if (rv != RecvResult::Complete) break; clif_charselectok(account_to_block(fixed.account_id)); break; } case 0x2b04: { Packet_Head<0x2b04> head; std::vector<Packet_Repeat<0x2b04>> repeat; rv = recv_vpacket<0x2b04, 10, 16>(s, head, repeat); if (rv != RecvResult::Complete) break; chrif_recvmap(s, head, repeat); break; } case 0x2b06: { Packet_Fixed<0x2b06> fixed; rv = recv_fpacket<0x2b06, 44>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changemapserverack(s, fixed); break; } case 0x2b0b: { Packet_Fixed<0x2b0b> fixed; rv = recv_fpacket<0x2b0b, 10>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changedgm(s, fixed); break; } case 0x2b0d: { Packet_Fixed<0x2b0d> fixed; rv = recv_fpacket<0x2b0d, 7>(s, fixed); if (rv != RecvResult::Complete) break; chrif_changedsex(s, fixed); break; } case 0x2b0f: { Packet_Fixed<0x2b0f> fixed; rv = recv_fpacket<0x2b0f, 34>(s, fixed); if (rv != RecvResult::Complete) break; chrif_char_ask_name_answer(s, fixed); break; } case 0x2b11: { Packet_Head<0x2b11> head; std::vector<Packet_Repeat<0x2b11>> repeat; rv = recv_vpacket<0x2b11, 8, 36>(s, head, repeat); if (rv != RecvResult::Complete) break; chrif_accountreg2(s, head, repeat); break; } case 0x2b12: { Packet_Fixed<0x2b12> fixed; rv = recv_fpacket<0x2b12, 10>(s, fixed); if (rv != RecvResult::Complete) break; chrif_divorce(fixed.char_id, fixed.partner_id); break; } case 0x2b13: { Packet_Fixed<0x2b13> fixed; rv = recv_fpacket<0x2b13, 6>(s, fixed); if (rv != RecvResult::Complete) break; chrif_accountdeletion(s, fixed); break; } case 0x2b14: { Packet_Fixed<0x2b14> fixed; rv = recv_fpacket<0x2b14, 11>(s, fixed); if (rv != RecvResult::Complete) break; chrif_accountban(s, fixed); break; } case 0x2b15: { std::vector<Packet_Repeat<0x2b15>> repeat; rv = recv_packet_repeatonly<0x2b15, 4, 5>(s, repeat); if (rv != RecvResult::Complete) break; chrif_recvgmaccounts(s, repeat); break; } default: { RecvResult r = intif_parse(s, packet_id); if (r == RecvResult::Complete) break; if (r == RecvResult::Incomplete) return; if (battle_config.error_log) PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s, packet_id); s->set_eof(); return; } } } if (rv == RecvResult::Error) s->set_eof(); }
/*========================================== * 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(Session *, const Packet_Fixed<0x2b0f>& fixed) { AccountId acc = fixed.account_id; // who asked, or nobody CharName player_name = fixed.char_name; dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc)); if (acc && sd != nullptr) { AString output; if (fixed.error == 1) // player not found output = STRPRINTF("The player '%s' doesn't exist."_fmt, player_name); else { switch (fixed.operation) { case 1: // block switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( "Login-server has been asked to block the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( "Your GM level don't authorise you to block the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( "Login-server is offline. Impossible to block the the player '%s'."_fmt, player_name); break; } break; case 2: // ban switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( "Login-server has been asked to ban the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( "Your GM level don't authorise you to ban the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( "Login-server is offline. Impossible to ban the the player '%s'."_fmt, player_name); break; } break; case 3: // unblock switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( "Login-server has been asked to unblock the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( "Your GM level don't authorise you to unblock the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( "Login-server is offline. Impossible to unblock the the player '%s'."_fmt, player_name); break; } break; case 4: // unban switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( "Login-server has been asked to unban the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( "Your GM level don't authorise you to unban the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( "Login-server is offline. Impossible to unban the the player '%s'."_fmt, player_name); break; } break; case 5: // changesex switch (fixed.error) { case 0: // login-server resquest done output = STRPRINTF( "Login-server has been asked to change the sex of the player '%s'."_fmt, player_name); break; //case 1: // player not found case 2: // gm level too low output = STRPRINTF( "Your GM level don't authorise you to change the sex of the player '%s'."_fmt, player_name); break; case 3: // login-server offline output = STRPRINTF( "Login-server is offline. Impossible to change the sex of the the player '%s'."_fmt, player_name); break; } break; } } if (output) clif_displaymessage(sd->sess, output); } else PRINTF("chrif_char_ask_name_answer failed - player not online.\n"_fmt); return 0; }
/* Process party invitation from sd to account_id. */ int party_invite(dumb_ptr<map_session_data> sd, AccountId account_id) { dumb_ptr<map_session_data> tsd = map_id2sd(account_to_block(account_id)); PartyPair p = party_search(sd->status.party_id); int i; int full = 1; /* Indicates whether or not there's room for one more. */ nullpo_retz(sd); if (!tsd || !p || !tsd->sess) return 0; if (!battle_config.invite_request_check) { /* Disallow the invitation under these conditions. */ if (tsd->trade_partner || tsd->npc_id || tsd->npc_shopid || pc_checkskill(tsd, SkillID::NV_PARTY) < 1) { clif_party_inviteack(sd, tsd->status_key.name, 1); return 0; } } /* The target player is already in a party, or has a pending invitation. */ if (tsd->status.party_id || tsd->party_invite) { clif_party_inviteack(sd, tsd->status_key.name, 0); return 0; } for (i = 0; i < MAX_PARTY; i++) { /* * A character from the target account is already in the same party. * The response isn't strictly accurate, as they're separate * characters, but we're making do with what was already in place and * leaving this (mostly) alone for now. */ if (p->member[i].account_id == account_id) { clif_party_inviteack(sd, tsd->status_key.name, 1); return 0; } if (!p->member[i].account_id) full = 0; } /* There isn't enough room for a new member. */ if (full) { clif_party_inviteack(sd, tsd->status_key.name, 3); return 0; } /* Otherwise, relay the invitation to the target player. */ tsd->party_invite = sd->status.party_id; tsd->party_invite_account = sd->status_key.account_id; clif_party_invite(sd, tsd); return 0; }
/*========================================== * アイテム追加 *------------------------------------------ */ void trade_tradeadditem(dumb_ptr<map_session_data> sd, IOff2 index, int amount) { dumb_ptr<map_session_data> target_sd; struct item_data *id; int trade_i; int trade_weight = 0; int free_ = 0; int c; nullpo_retv(sd); if (((target_sd = map_id2sd(account_to_block(sd->trade_partner))) != nullptr) && (sd->deal_locked < 1)) { if (!index.ok()) { if (index.index == 0 && amount > 0 && amount <= sd->status.zeny) { sd->deal_zeny = amount; clif_tradeadditem(sd, target_sd, index, amount); } } // note: amount is overridden below! else if (amount <= sd->status.inventory[index.unshift()].amount && amount > 0) { // determine free slots of receiver for (IOff0 i : IOff0::iter()) { if (!target_sd->status.inventory[i].nameid && target_sd->inventory_data[i] == nullptr) free_++; } for (trade_i = 0; trade_i < TRADE_MAX; trade_i++) { if (sd->deal_item_amount[trade_i] == 0) { // calculate trade weight trade_weight += sd->inventory_data[index.unshift()]->weight * amount; // determine if item is a stackable already in receivers inventory, and up free count for (IOff0 i : IOff0::iter()) { if (target_sd->status.inventory[i].nameid == sd->status.inventory[index.unshift()].nameid && target_sd->inventory_data[i] != nullptr) { id = target_sd->inventory_data[i]; if (id->type != ItemType::WEAPON && id->type != ItemType::ARMOR && id->type != ItemType::_7 && id->type != ItemType::_8) { free_++; break; } } } if (target_sd->weight + trade_weight > target_sd->max_weight) { clif_tradeitemok(sd, index, 0, 1); //fail to add item -- the player was over weighted. amount = 0; // [MouseJstr] } else if (free_ <= 0) { clif_tradeitemok(sd, index, 0, 2); //fail to add item -- no free slots at receiver amount = 0; // peavey } else { for (c = 0; c == trade_i - 1; c++) { // re-deal exploit protection [Valaris] if (sd->deal_item_index[c] == index) { trade_tradecancel(sd); return; } } pc_unequipinvyitem(sd, index.unshift(), CalcStatus::NOW); sd->deal_item_index[trade_i] = index; sd->deal_item_amount[trade_i] += amount; clif_tradeitemok(sd, index, amount, 0); //success to add item clif_tradeadditem(sd, target_sd, index, amount); } break; } else { // calculate weight for stored deal trade_weight += sd->inventory_data[sd->deal_item_index[trade_i].unshift() ]->weight * sd->deal_item_amount[trade_i]; // count free stackables in stored deal for (IOff0 i : IOff0::iter()) { if (target_sd->status.inventory[i].nameid == sd->status. inventory[sd->deal_item_index[trade_i].unshift()].nameid && target_sd->inventory_data[i] != nullptr) { id = target_sd->inventory_data[i]; if (id->type != ItemType::WEAPON && id->type != ItemType::ARMOR && id->type != ItemType::_7 && id->type != ItemType::_8) { free_++; break; } } } } // used a slot, but might be cancelled out by stackable checks above free_--; } } } }
/*========================================== * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] *------------------------------------------ */ static int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed) { dumb_ptr<map_session_data> sd; AccountId acc = fixed.account_id; if (battle_config.etc_log) PRINTF("chrif_accountban %d.\n"_fmt, acc); sd = map_id2sd(account_to_block(acc)); if (acc) { if (sd != nullptr) { sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters if (fixed.ban_not_status == 0) { // 0: change of statut, 1: ban switch (static_cast<time_t>(fixed.status_or_ban_until)) { // status or final date of a banishment case 1: // 0 = Unregistered ID clif_displaymessage(sd->sess, "Your account has 'Unregistered'."_s); break; case 2: // 1 = Incorrect Password clif_displaymessage(sd->sess, "Your account has an 'Incorrect Password'..."_s); break; case 3: // 2 = This ID is expired clif_displaymessage(sd->sess, "Your account has expired."_s); break; case 4: // 3 = Rejected from Server clif_displaymessage(sd->sess, "Your account has been rejected from server."_s); break; case 5: // 4 = You have been blocked by the GM Team clif_displaymessage(sd->sess, "Your account has been blocked by the GM Team."_s); break; case 6: // 5 = Your Game's EXE file is not the latest version clif_displaymessage(sd->sess, "Your Game's EXE file is not the latest version."_s); break; case 7: // 6 = Your are Prohibited to log in until %s clif_displaymessage(sd->sess, "Your account has been prohibited to log in."_s); break; case 8: // 7 = Server is jammed due to over populated clif_displaymessage(sd->sess, "Server is jammed due to over populated."_s); break; case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) clif_displaymessage(sd->sess, "Your account has not more authorised."_s); break; case 100: // 99 = This ID has been totally erased clif_displaymessage(sd->sess, "Your account has been totally erased."_s); break; default: clif_displaymessage(sd->sess, "Your account has not more authorised."_s); break; } } else if (fixed.ban_not_status == 1) { // 0: change of statut, 1: ban const TimeT timestamp = fixed.status_or_ban_until; // status or final date of a banishment timestamp_seconds_buffer buffer; stamp_time(buffer, ×tamp); AString tmpstr = STRPRINTF("Your account has been banished until %s"_fmt, buffer); clif_displaymessage(sd->sess, tmpstr); } clif_setwaitclose(sd->sess); // forced to disconnect for the change } } else { if (sd != nullptr) PRINTF("chrif_accountban failed - player not online.\n"_fmt); } return 0; }