// $Id: int_party.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ #include "inter.hpp" #include "int_party.hpp" #include "../common/mmo.hpp" #include "char.hpp" #include "../common/socket.hpp" #include "../common/db.hpp" #include "../common/lock.hpp" #include #include #include char party_txt[1024] = "save/party.txt"; static struct dbt *party_db; static int party_newid = 100; int mapif_party_broken (int party_id, int flag); int party_check_empty (struct party *p); int mapif_parse_PartyLeave (int fd, int party_id, int account_id); // パーティデータの文字列への変換 static int inter_party_tostr (char *str, struct party *p) { int i, len; len = sprintf (str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item); for (i = 0; i < MAX_PARTY; i++) { struct party_member *m = &p->member[i]; len += sprintf (str + len, "%d,%d\t%s\t", m->account_id, m->leader, ((m->account_id > 0) ? m->name : "NoMember")); } return 0; } // パーティデータの文字列からの変換 static int inter_party_fromstr (char *str, struct party *p) { int i, j; int tmp_int[16]; char tmp_str[256]; memset (p, 0, sizeof (struct party)); // printf("sscanf party main info\n"); if (sscanf (str, "%d\t%[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4) return 1; p->party_id = tmp_int[0]; strcpy (p->name, tmp_str); p->exp = tmp_int[1]; p->item = tmp_int[2]; // printf("%d [%s] %d %d\n", tmp_int[0], tmp_str[0], tmp_int[1], tmp_int[2]); for (j = 0; j < 3 && str != NULL; j++) str = strchr (str + 1, '\t'); for (i = 0; i < MAX_PARTY; i++) { struct party_member *m = &p->member[i]; if (str == NULL) return 1; // printf("sscanf party member info %d\n", i); if (sscanf (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], tmp_str) != 3) return 1; m->account_id = tmp_int[0]; m->leader = tmp_int[1]; strncpy (m->name, tmp_str, sizeof (m->name)); // printf(" %d %d [%s]\n", tmp_int[0], tmp_int[1], tmp_str); for (j = 0; j < 2 && str != NULL; j++) str = strchr (str + 1, '\t'); } return 0; } // パーティデータのロード int inter_party_init (void) { char line[8192]; struct party *p; FILE *fp; int c = 0; int i, j; party_db = numdb_init (); if ((fp = fopen_ (party_txt, "r")) == NULL) return 1; while (fgets (line, sizeof (line) - 1, fp)) { j = 0; if (sscanf (line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { party_newid = i; continue; } CREATE (p, struct party, 1); if (inter_party_fromstr (line, p) == 0 && p->party_id > 0) { if (p->party_id >= party_newid) party_newid = p->party_id + 1; numdb_insert (party_db, p->party_id, p); party_check_empty (p); } else { printf ("int_party: broken data [%s] line %d\n", party_txt, c + 1); free (p); } c++; } fclose_ (fp); // printf("int_party: %s read done (%d parties)\n", party_txt, c); return 0; } // パーティーデータのセーブ用 static void inter_party_save_sub (db_key_t key, db_val_t data, va_list ap) { char line[8192]; FILE *fp; inter_party_tostr (line, (struct party *) data); fp = va_arg (ap, FILE *); fprintf (fp, "%s\n", line); } // パーティーデータのセーブ int inter_party_save (void) { FILE *fp; int lock; if ((fp = lock_fopen (party_txt, &lock)) == NULL) { printf ("int_party: cant write [%s] !!! data is lost !!!\n", party_txt); return 1; } numdb_foreach (party_db, inter_party_save_sub, fp); // fprintf(fp, "%d\t%%newid%%\n", party_newid); lock_fclose (fp, party_txt, &lock); // printf("int_party: %s saved.\n", party_txt); return 0; } // パーティ名検索用 static void search_partyname_sub (db_key_t key, db_val_t data, va_list ap) { struct party *p = (struct party *) data, **dst; char *str; str = va_arg (ap, char *); dst = va_arg (ap, struct party **); if (strcasecmp (p->name, str) == 0) *dst = p; } // パーティ名検索 static struct party *search_partyname (const char *str) { struct party *p = NULL; numdb_foreach (party_db, search_partyname_sub, str, &p); return p; } // EXP公平分配できるかチェック static int party_check_exp_share (struct party *p) { int i; int maxlv = 0, minlv = 0x7fffffff; for (i = 0; i < MAX_PARTY; i++) { int lv = p->member[i].lv; if (p->member[i].online) { if (lv < minlv) minlv = lv; if (maxlv < lv) maxlv = lv; } } return (maxlv == 0 || maxlv - minlv <= party_share_level); } // パーティが空かどうかチェック int party_check_empty (struct party *p) { int i; // printf("party check empty %08X\n", (int)p); for (i = 0; i < MAX_PARTY; i++) { // printf("%d acc=%d\n", i, p->member[i].account_id); if (p->member[i].account_id > 0) { return 0; } } // 誰もいないので解散 mapif_party_broken (p->party_id, 0); numdb_erase (party_db, p->party_id); free (p); return 1; } // キャラの競合がないかチェック用 static void party_check_conflict_sub (db_key_t key, db_val_t data, va_list ap) { struct party *p = (struct party *) data; int party_id, account_id, i; char *nick; party_id = va_arg (ap, int); account_id = va_arg (ap, int); nick = va_arg (ap, char *); if (p->party_id == party_id) // 本来の所属なので問題なし return; for (i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id == account_id && strcmp (p->member[i].name, nick) == 0) { // 別のパーティに偽の所属データがあるので脱退 printf ("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party_id); mapif_parse_PartyLeave (-1, p->party_id, account_id); } } } // キャラの競合がないかチェック static int party_check_conflict (int party_id, int account_id, const char *nick) { numdb_foreach (party_db, party_check_conflict_sub, party_id, account_id, nick); return 0; } //------------------------------------------------------------------- // map serverへの通信 // パーティ作成可否 static int mapif_party_created (int fd, int account_id, struct party *p) { WFIFOW (fd, 0) = 0x3820; WFIFOL (fd, 2) = account_id; if (p != NULL) { WFIFOB (fd, 6) = 0; WFIFOL (fd, 7) = p->party_id; memcpy (WFIFOP (fd, 11), p->name, 24); printf ("int_party: created! %d %s\n", p->party_id, p->name); } else { WFIFOB (fd, 6) = 1; WFIFOL (fd, 7) = 0; memcpy (WFIFOP (fd, 11), "error", 24); } WFIFOSET (fd, 35); return 0; } // パーティ情報見つからず static int mapif_party_noinfo (int fd, int party_id) { WFIFOW (fd, 0) = 0x3821; WFIFOW (fd, 2) = 8; WFIFOL (fd, 4) = party_id; WFIFOSET (fd, 8); printf ("int_party: info not found %d\n", party_id); return 0; } // パーティ情報まとめ送り static int mapif_party_info (int fd, struct party *p) { unsigned char buf[4 + sizeof (struct party)]; WBUFW (buf, 0) = 0x3821; memcpy (buf + 4, p, sizeof (struct party)); WBUFW (buf, 2) = 4 + sizeof (struct party); if (fd < 0) mapif_sendall (buf, WBUFW (buf, 2)); else mapif_send (fd, buf, WBUFW (buf, 2)); // printf("int_party: info %d %s\n", p->party_id, p->name); return 0; } // パーティメンバ追加可否 static int mapif_party_memberadded (int fd, int party_id, int account_id, int flag) { WFIFOW (fd, 0) = 0x3822; WFIFOL (fd, 2) = party_id; WFIFOL (fd, 6) = account_id; WFIFOB (fd, 10) = flag; WFIFOSET (fd, 11); return 0; } // パーティ設定変更通知 static int mapif_party_optionchanged (int fd, struct party *p, int account_id, int flag) { unsigned char buf[15]; 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); printf ("int_party: option changed %d %d %d %d %d\n", p->party_id, account_id, p->exp, p->item, flag); return 0; } // パーティ脱退通知 static int mapif_party_leaved (int party_id, int account_id, char *name) { unsigned char buf[34]; WBUFW (buf, 0) = 0x3824; WBUFL (buf, 2) = party_id; WBUFL (buf, 6) = account_id; memcpy (WBUFP (buf, 10), name, 24); mapif_sendall (buf, 34); printf ("int_party: party leaved %d %d %s\n", party_id, account_id, name); return 0; } // パーティマップ更新通知 static int mapif_party_membermoved (struct party *p, int idx) { unsigned char buf[29]; WBUFW (buf, 0) = 0x3825; WBUFL (buf, 2) = p->party_id; WBUFL (buf, 6) = p->member[idx].account_id; memcpy (WBUFP (buf, 10), p->member[idx].map, 16); WBUFB (buf, 26) = p->member[idx].online; WBUFW (buf, 27) = p->member[idx].lv; mapif_sendall (buf, 29); return 0; } // パーティ解散通知 int mapif_party_broken (int party_id, int flag) { unsigned char buf[7]; 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; } // パーティ内発言 static int mapif_party_message (int party_id, int account_id, const char *mes, int len) { unsigned char buf[len + 12]; 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_sendall (buf, len + 12); return 0; } //------------------------------------------------------------------- // map serverからの通信 // パーティ static int mapif_parse_CreateParty (int fd, int account_id, const char *name, const char *nick, const char *map, int lv) { struct party *p; int i; for (i = 0; i < 24 && name[i]; i++) { if (!(name[i] & 0xe0) || name[i] == 0x7f) { printf ("int_party: illegal party name [%s]\n", name); mapif_party_created (fd, account_id, NULL); return 0; } } if ((p = search_partyname (name)) != NULL) { printf ("int_party: same name party exists [%s]\n", name); mapif_party_created (fd, account_id, NULL); return 0; } CREATE (p, struct party, 1); p->party_id = party_newid++; memcpy (p->name, name, 24); p->exp = 0; p->item = 0; p->member[0].account_id = account_id; memcpy (p->member[0].name, nick, 24); memcpy (p->member[0].map, map, 16); p->member[0].leader = 1; p->member[0].online = 1; p->member[0].lv = lv; numdb_insert (party_db, p->party_id, p); mapif_party_created (fd, account_id, p); mapif_party_info (fd, p); return 0; } // パーティ情報要求 static int mapif_parse_PartyInfo (int fd, int party_id) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p != NULL) mapif_party_info (fd, p); else mapif_party_noinfo (fd, party_id); return 0; } // パーティ追加要求 static int mapif_parse_PartyAddMember (int fd, int party_id, int account_id, const char *nick, const char *map, int lv) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p == NULL) { mapif_party_memberadded (fd, party_id, account_id, 1); return 0; } for (int i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id == 0) { int flag = 0; p->member[i].account_id = account_id; memcpy (p->member[i].name, nick, 24); memcpy (p->member[i].map, map, 16); p->member[i].leader = 0; p->member[i].online = 1; p->member[i].lv = lv; mapif_party_memberadded (fd, party_id, account_id, 0); mapif_party_info (-1, p); if (p->exp > 0 && !party_check_exp_share (p)) { p->exp = 0; flag = 0x01; } if (flag) mapif_party_optionchanged (fd, p, 0, 0); return 0; } } mapif_party_memberadded (fd, party_id, account_id, 1); return 0; } // パーティー設定変更要求 static int mapif_parse_PartyChangeOption (int fd, int party_id, int account_id, int exp, int item) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p == NULL) return 0; p->exp = exp; int flag = 0; if (exp > 0 && !party_check_exp_share (p)) { flag |= 0x01; p->exp = 0; } p->item = item; mapif_party_optionchanged (fd, p, account_id, flag); return 0; } // パーティ脱退要求 int mapif_parse_PartyLeave (int fd, int party_id, int account_id) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p != NULL) { for (int i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id == account_id) { mapif_party_leaved (party_id, account_id, p->member[i].name); memset (&p->member[i], 0, sizeof (struct party_member)); if (party_check_empty (p) == 0) mapif_party_info (-1, p); // まだ人がいるのでデータ送信 return 0; } } } return 0; } // パーティマップ更新要求 static int mapif_parse_PartyChangeMap (int fd, int party_id, int account_id, const char *map, int online, int lv) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p == NULL) return 0; for (int i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id == account_id) { int flag = 0; memcpy (p->member[i].map, map, 16); p->member[i].online = online; p->member[i].lv = lv; mapif_party_membermoved (p, i); if (p->exp > 0 && !party_check_exp_share (p)) { p->exp = 0; flag = 1; } if (flag) mapif_party_optionchanged (fd, p, 0, 0); break; } } return 0; } // パーティ解散要求 static int mapif_parse_BreakParty (int fd, int party_id) { struct party *p = (struct party *)numdb_search (party_db, party_id); if (p == NULL) return 0; numdb_erase (party_db, party_id); mapif_party_broken (fd, party_id); return 0; } // パーティメッセージ送信 static int mapif_parse_PartyMessage (int fd, int party_id, int account_id, const char *mes, int len) { return mapif_party_message (party_id, account_id, mes, len); } // パーティチェック要求 static int mapif_parse_PartyCheck (int fd, int party_id, int account_id, const char *nick) { return party_check_conflict (party_id, account_id, nick); } // map server からの通信 // ・1パケットのみ解析すること // ・パケット長データはinter.cにセットしておくこと // ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない // ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない int inter_party_parse_frommap (int fd) { switch (RFIFOW (fd, 0)) { case 0x3020: mapif_parse_CreateParty (fd, RFIFOL (fd, 2), (const char *)RFIFOP (fd, 6), (const char *)RFIFOP (fd, 30), (const char *)RFIFOP (fd, 54), RFIFOW (fd, 70)); break; case 0x3021: mapif_parse_PartyInfo (fd, RFIFOL (fd, 2)); break; case 0x3022: mapif_parse_PartyAddMember (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), (const char *)RFIFOP (fd, 10), (const char *)RFIFOP (fd, 34), RFIFOW (fd, 50)); 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)); break; case 0x3025: mapif_parse_PartyChangeMap (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), (const char *)RFIFOP (fd, 10), RFIFOB (fd, 26), RFIFOW (fd, 27)); break; case 0x3026: mapif_parse_BreakParty (fd, RFIFOL (fd, 2)); break; case 0x3027: mapif_parse_PartyMessage (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), (const char *)RFIFOP (fd, 12), RFIFOW (fd, 2) - 12); break; case 0x3028: mapif_parse_PartyCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), (const char *)RFIFOP (fd, 10)); break; default: return 0; } return 1; } // サーバーから脱退要求(キャラ削除用) int inter_party_leave (int party_id, int account_id) { return mapif_parse_PartyLeave (-1, party_id, account_id); }