summaryrefslogblamecommitdiff
path: root/src/char/int_party.c
blob: e80a5de63057f48b8466d53a51713c25ac19e4c7 (plain) (tree)
1
2
3
4
5
6
7





                                                           
                    











                                         






                                                      





                                                                               




                                                                                 

                         





















                                                               

                         
































                                                               







                                                                                      
                                                                                               









                                                      

                                       




















                                                                                                        
                                                                                               




                                            
 










                                                                      







                         
                              















                                                                                                   
                                                                               



                                                                       






                                                                                          





















                                                                                              
                                                                     





















                                                                                           
                                                                


                                  

                                                            





                          

                                                 




                                                                    



                                                                                                   


















                                                                  
                                                          





                                              
                                                                  


                                         




                                                                                                                       





























































































                                                                                                 
                              







                                         

                                                                  
                  




                                                                   

                               




























































                                                                                     

                                                                                                    




                                                                                
                                                                                            





                                                                            
                                                                                    

                          




                                                                                                 
                                                                                                    




                                                                                                  
                                                                                                    



                                          
                                                                         

                                                                
                                                                                 

                          










                                                                                 





                                                  
                              


                                         
                                                 
               
                                                  

                                           




                   

                                                                                    


                                         

                                                                                               



                                         




                                                                                          



                                                                                             

                                                                                     
                          

                                                                                                       


                                  
                                                                                       




                       
                                                                                             
                              
                      




                                         
                            

                                                  
                                  
          
                                  
                                                                    




                                                                                

                              

                                         











                                                                                     
                          

                                                                                    
                          


                                                                 

                  


                  
                                                                                                                                   
  
                              






                                         

                                                                  
                  
                                                      

                                                                 
                                                                    













                                                                                                                          
                                  








                                                                            
                          
                                                               


                               




                                                   

















                                                                                         
                              







                                         




                                                                  











                                                                              
                                                                                                                                                 
                                                                     
                                                                                                              


















                                                                                                                                                    
// 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 <limits.h>

#include "../common/mmo.h"
#include "../common/socket.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/showmsg.h"
#include "char.h"
#include "inter.h"
#include "int_party.h"

char party_txt[1024] = "save/party.txt";

struct party_data {
	struct party party;
	unsigned int min_lv, max_lv;
	unsigned char size; //Total size of party.
	unsigned family :1; //Is this party a family?
};

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 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);

//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, max/min levels.
	for(i=0;i<MAX_PARTY;i++){
		lv=p->party.member[i].lv;
		if (!lv) continue;
		p->size++;
		if(p->party.member[i].online)
		{
			if( lv < p->min_lv ) p->min_lv=lv;
			if( p->max_lv < lv ) p->max_lv=lv;
			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
		);
	}

	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;
}

// �p?�e�B�f?�^�̕�����ւ�?��
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,%d\t", m->account_id, m->char_id, m->leader);
	}

	return 0;
}

// �p?�e�B�f?�^�̕����񂩂��?��
int inter_party_fromstr(char *str, struct party *p) {
	int i, j;
	int tmp_int[16];
	char tmp_str[256];
	struct mmo_charstatus* status;
	
	memset(p, 0, sizeof(struct party));

//	printf("sscanf party main info\n");
	if (sscanf(str, "%d\t%255[^\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];
	memcpy(p->name, tmp_str, NAME_LENGTH-1);
	p->exp = tmp_int[1]?1:0;
	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,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3)
			return 1;

		m->account_id = tmp_int[0];
		m->char_id = tmp_int[1]; 
		m->leader = tmp_int[2]?1:0;

		str = strchr(str + 1, '\t');

		if (!m->account_id) continue;
		//Lookup player for rest of data.
		status = search_character(m->account_id, m->char_id);
		if (!status) continue;
		
		memcpy(m->name, status->name, NAME_LENGTH);
		m->class_ = status->class_;
		m->map = status->last_point.map;
		m->lv = status->base_level;
	}

	return 0;
}

// �p?�e�B�f?�^�̃�?�h
int inter_party_init() {
	char line[8192];
	struct party_data *p;
	FILE *fp;
	int c = 0;
	int i, j;

	party_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));

	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 = (struct party_data*)aCalloc(sizeof(struct party_data), 1);
		if (p == NULL){
			ShowFatalError("int_party: out of memory!\n");
			exit(0);
		}
		memset(p, 0, sizeof(struct party_data));
		if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) {
			int_party_calc_state(p);
			if (p->party.party_id >= party_newid)
				party_newid = p->party.party_id + 1;
			idb_put(party_db, p->party.party_id, p);
			party_check_empty(&p->party);
		} else {
			ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1);
			aFree(p);
		}
		c++;
	}
	fclose(fp);

	return 0;
}

void inter_party_final()
{
	party_db->destroy(party_db, NULL);
	return;
}

// �p?�e�B?�f?�^�̃Z?�u�p
int inter_party_save_sub(DBKey key, void *data, va_list ap) {
	char line[8192];
	FILE *fp;

	inter_party_tostr(line, &((struct party_data*)data)->party);
	fp = va_arg(ap, FILE *);
	fprintf(fp, "%s" RETCODE, line);

	return 0;
}

// �p?�e�B?�f?�^�̃Z?�u
int inter_party_save() {
	FILE *fp;
	int lock;

	if ((fp = lock_fopen(party_txt, &lock)) == NULL) {
		ShowError("int_party: cant write [%s] !!! data is lost !!!\n", party_txt);
		return 1;
	}
	party_db->foreach(party_db, inter_party_save_sub, fp);
	lock_fclose(fp,party_txt, &lock);
	return 0;
}

// �p?�e�B��?���p
int search_partyname_sub(DBKey key,void *data,va_list ap) {
	struct party_data *p = (struct party_data *)data,**dst;
	char *str;

	str = va_arg(ap, char *);
	dst = va_arg(ap, struct party_data **);
	if (strncmpi(p->party.name, str, NAME_LENGTH) == 0)
		*dst = p;

	return 0;
}

// �p?�e�B��?��
struct party_data* search_partyname(char *str) {
	struct party_data *p = NULL;
	party_db->foreach(party_db, search_partyname_sub, str, &p);
	return p;
}

// EXP�������z�ł��邩�`�F�b�N
int party_check_exp_share(struct party_data *p) {
	return (p->party.count == 0 || //If noone is online, don't mess with the share type.
		(p->family && p->party.count == 3) || //All 3 MUST be online for share to trigger.
	  	p->max_lv - p->min_lv <= party_share_level);
}

// �p?�e�B���󂩂ǂ����`�F�b�N
int party_check_empty(struct party *p) {
	int i;

	for(i = 0; i < MAX_PARTY; i++) {
		if (p->member[i].account_id > 0) {
			return 0;
		}
	}
	mapif_party_broken(p->party_id, 0);
	idb_remove(party_db, p->party_id);

	return 1;
}

// �L�����̋������Ȃ����`�F�b�N�p
int party_check_conflict_sub(DBKey key, void *data, va_list ap) {
	struct party_data *p = (struct party_data *)data;
	int party_id, account_id, char_id, i;

	party_id=va_arg(ap, int);
	account_id=va_arg(ap, int);
	char_id=va_arg(ap, int);
	
	if (p->party.party_id == party_id) //No conflict to check
		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)
	  	{
			ShowWarning("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party.party_id);
			mapif_parse_PartyLeave(-1, p->party.party_id, account_id, char_id);
		}
	}

	return 0;
}

// �L�����̋������Ȃ����`�F�b�N
int party_check_conflict(int party_id, int account_id, int char_id) {
	party_db->foreach(party_db, party_check_conflict_sub, party_id, account_id, 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("Created party (%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[2048];

	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));
	return 0;
}

// �p?�e�B�����o�lj��”�
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[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);
	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)
		return 0;

	p = idb_get(party_db, 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].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?�ޒʒ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[7];
	WBUFW(buf,0) = 0x3826;
	WBUFL(buf,2) = party_id;
	WBUFB(buf,6) = flag;
	mapif_sendall(buf, 7);
	ShowInfo("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[2048];

	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


// �p?�e�B
int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) {
	struct party_data *p;
	int i;

	for(i = 0; i < NAME_LENGTH && name[i]; i++) {
		if (!(name[i] & 0xe0) || name[i] == 0x7f) {
			ShowInfo("int_party: illegal party name [%s]\n", name);
			mapif_party_created(fd, leader->account_id, leader->char_id, NULL);
			return 0;
		}
	}

	if ((p = search_partyname(name)) != NULL) {
		ShowInfo("int_party: same name party exists [%s]\n", name);
		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 = (struct party_data *) aCalloc(sizeof(struct party_data), 1);
	if (p == NULL) {
		ShowFatalError("int_party: out of memory !\n");
		mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
		return 0;
	}
	p->party.party_id = party_newid++;
	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;
	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);

	return 0;
}

// �p?�e�B���v��
int mapif_parse_PartyInfo(int fd, int party_id) {
	struct party_data *p;

	p = idb_get(party_db, party_id);
	if (p != NULL)
		mapif_party_info(fd, &p->party);
	else {
		mapif_party_noinfo(fd, party_id);
		char_clearparty(party_id);
	}

	return 0;
}

// �p?�e�B�lj��v��
int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) {
	struct party_data *p;
	int i;

	p = idb_get(party_db, party_id);
	if (p == NULL || 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 == 0) {
			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);
			return 0;
		}
	}
	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 = idb_get(party_db, party_id);
	if (p == NULL)
		return 0;

	p->party.exp = exp;
	if (exp>0 && !party_check_exp_share(p)) {
		flag |= 0x01;
		p->party.exp = 0;
	}
	p->party.item = item&0x3;
	mapif_party_optionchanged(fd, &p->party, account_id, flag);
	return 0;
}

// �p?�e�B?�ޗv��
int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) {
	struct party_data *p;
	int i,lv;

	p = idb_get(party_db, party_id);
	if (!p) 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)
		{
			mapif_party_leaved(party_id, account_id, char_id);
			lv = 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 (lv == p->min_lv || lv == p->max_lv || p->family)
			{
				if(p->family) p->family = 0; //Family state broken.
				int_party_check_lv(p);
			}
			if (party_check_empty(&p->party) == 0)
				mapif_party_info(-1, &p->party);
			return 0;
		}
	}
	return 0;
}

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 = idb_get(party_db, 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) {

	idb_remove(party_db, party_id);
	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 = idb_get(party_db, party_id);
	if (p == NULL)
		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;
	}
	return 1;
}

// map server ����̒ʐM
// ?�P�p�P�b�g�̂݉�͂��邱��
// ?�p�P�b�g���f?�^��inter.c�ɃZ�b�g���Ă�������
// ?�p�P�b�g���`�F�b�N��ARFIFOSKIP�͌Ăяo�����ōs����̂ōs���Ă͂Ȃ�Ȃ�
// ?�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?����?�ޗ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);
}