// $Id: int_party.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $
#include "inter.h"
#include "int_party.h"
#include "mmo.h"
#include "char.h"
#include "socket.h"
#include "db.h"
#include "lock.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
// パーティデータの文字列への変換
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;
}
// パーティデータの文字列からの変換
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 ()
{
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;
}
p = calloc (sizeof (struct party), 1);
if (p == NULL)
{
printf ("int_party: out of memory!\n");
exit (0);
}
memset (p, 0, sizeof (struct party));
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;
}
// パーティーデータのセーブ用
int inter_party_save_sub (void *key, void *data, va_list ap)
{
char line[8192];
FILE *fp;
inter_party_tostr (line, (struct party *) data);
fp = va_arg (ap, FILE *);
fprintf (fp, "%s" RETCODE, line);
return 0;
}
// パーティーデータのセーブ
int inter_party_save ()
{
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;
}
// パーティ名検索用
int search_partyname_sub (void *key, void *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 (strcmpi (p->name, str) == 0)
*dst = p;
return 0;
}
// パーティ名検索
struct party *search_partyname (char *str)
{
struct party *p = NULL;
numdb_foreach (party_db, search_partyname_sub, str, &p);
return p;
}
// EXP公平分配できるかチェック
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;
}
// キャラの競合がないかチェック用
int party_check_conflict_sub (void *key, void *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 0;
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);
}
}
return 0;
}
// キャラの競合がないかチェック
int party_check_conflict (int party_id, int account_id, char *nick)
{
numdb_foreach (party_db, party_check_conflict_sub, party_id, account_id,
nick);
return 0;
}
//-------------------------------------------------------------------
// map serverへの通信
// パーティ作成可否
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;
}
// パーティ情報見つからず
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;
}
// パーティ情報まとめ送り
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;
}
// パーティメンバ追加可否
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;
}
// パーティ設定変更通知
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;
}
// パーティ脱退通知
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;
}
// パーティマップ更新通知
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;
}
// パーティ内発言
int mapif_party_message (int party_id, int account_id, 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からの通信
// パーティ
int mapif_parse_CreateParty (int fd, int account_id, char *name, char *nick,
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;
}
p = calloc (sizeof (struct party), 1);
if (p == NULL)
{
printf ("int_party: out of memory !\n");
mapif_party_created (fd, account_id, NULL);
return 0;
}
memset (p, 0, sizeof (struct party));
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;
}
// パーティ情報要求
int mapif_parse_PartyInfo (int fd, int party_id)
{
struct party *p;
p = numdb_search (party_db, party_id);
if (p != NULL)
mapif_party_info (fd, p);
else
mapif_party_noinfo (fd, party_id);
return 0;
}
// パーティ追加要求
int mapif_parse_PartyAddMember (int fd, int party_id, int account_id,
char *nick, char *map, int lv)
{
struct party *p;
int i;
p = numdb_search (party_db, party_id);
if (p == NULL)
{
mapif_party_memberadded (fd, party_id, account_id, 1);
return 0;
}
for (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;
}
// パーティー設定変更要求
int mapif_parse_PartyChangeOption (int fd, int party_id, int account_id,
int exp, int item)
{
struct party *p;
int flag = 0;
p = numdb_search (party_db, party_id);
if (p == NULL)
return 0;
p->exp = exp;
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;
int i;
p = numdb_search (party_db, party_id);
if (p != NULL)
{
for (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;
}
// パーティマップ更新要求
int mapif_parse_PartyChangeMap (int fd, int party_id, int account_id,
char *map, int online, int lv)
{
struct party *p;
int i;
p = numdb_search (party_db, party_id);
if (p == NULL)
return 0;
for (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;
}
// パーティ解散要求
int mapif_parse_BreakParty (int fd, int party_id)
{
struct party *p;
p = 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;
}
// パーティメッセージ送信
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);
}
// パーティチェック要求
int mapif_parse_PartyCheck (int fd, int party_id, int account_id, 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), RFIFOP (fd, 6),
RFIFOP (fd, 30), 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),
RFIFOP (fd, 10), 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),
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),
RFIFOP (fd, 12), RFIFOW (fd, 2) - 12);
break;
case 0x3028:
mapif_parse_PartyCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6),
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);
}