rathena/src/char_sql/int_party.c
ultramage a08c56007a Corrected a problem where a party invite acknowledgement would not be sent (bugreport:1091).
There is still the unresolved issue where newly added party members will not display their party correctly.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12328 54d463be-8e91-2dee-dedb-b68131a5f0ec
2008-03-08 23:03:06 +00:00

876 lines
24 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/cbasetypes.h"
#include "../common/mmo.h"
#include "../common/db.h"
#include "../common/malloc.h"
#include "../common/strlib.h"
#include "../common/socket.h"
#include "../common/showmsg.h"
#include "../common/mapindex.h"
#include "../common/sql.h"
#include "char.h"
#include "inter.h"
#include "int_party.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef TXT_SQL_CONVERT
struct party_data {
struct party party;
unsigned int min_lv, max_lv;
int family; //Is this party a family? if so, this holds the child id.
unsigned char size; //Total size of party.
};
static struct party_data *party_pt;
static DBMap* party_db_; // int party_id -> struct party_data*
int mapif_party_broken(int party_id,int flag);
int party_check_empty(struct party_data *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
for(i=0;i<MAX_PARTY;i++){
if (!p->party.member[i].lv) continue;
p->size++;
if(p->party.member[i].online)
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
);
}
//max/min levels.
for(i=0;i<MAX_PARTY;i++){
lv=p->party.member[i].lv;
if (!lv) continue;
if(p->party.member[i].online &&
//On families, the kid is not counted towards exp share rules.
p->party.member[i].char_id != p->family)
{
if( lv < p->min_lv ) p->min_lv=lv;
if( p->max_lv < lv ) p->max_lv=lv;
}
}
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;
}
#endif //TXT_SQL_CONVERT
// Save party to mysql
int inter_party_tosql(struct party *p, int flag, int index)
{
// 'party' ('party_id','name','exp','item','leader_id','leader_char')
char esc_name[NAME_LENGTH*2+1];// escaped party name
int party_id;
if( p == NULL || p->party_id == 0 )
return 0;
party_id = p->party_id;
#ifdef NOISY
ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name);
#endif
Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH));
#ifndef TXT_SQL_CONVERT
if( flag & PS_BREAK )
{// Break the party
// we'll skip name-checking and just reset everyone with the same party id [celest]
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) )
Sql_ShowDebug(sql_handle);
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) )
Sql_ShowDebug(sql_handle);
//Remove from memory
idb_remove(party_db_, party_id);
return 1;
}
#endif //TXT_SQL_CONVERT
if( flag & PS_CREATE )
{// Create party
#ifndef TXT_SQL_CONVERT
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` "
"(`name`, `exp`, `item`, `leader_id`, `leader_char`) "
"VALUES ('%s', '%d', '%d', '%d', '%d')",
party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) )
{
Sql_ShowDebug(sql_handle);
return 0;
}
party_id = p->party_id = (int)Sql_LastInsertId(sql_handle);
#else
//During conversion, you want to specify the id, and allow overwriting
//(in case someone is re-running the process.
if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` "
"(`party_id`, `name`, `exp`, `item`, `leader_id`, `leader_char`) "
"VALUES ('%d', '%s', '%d', '%d', '%d', '%d')",
party_db, p->party_id, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) )
{
Sql_ShowDebug(sql_handle);
return 0;
}
#endif
}
#ifndef TXT_SQL_CONVERT
if( flag & PS_BASIC )
{// Update party info.
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'",
party_db, esc_name, p->exp, p->item, party_id) )
Sql_ShowDebug(sql_handle);
}
if( flag & PS_LEADER )
{// Update leader
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'",
party_db, p->member[index].account_id, p->member[index].char_id, party_id) )
Sql_ShowDebug(sql_handle);
}
if( flag & PS_ADDMEMBER )
{// Add one party member.
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'",
char_db, party_id, p->member[index].account_id, p->member[index].char_id) )
Sql_ShowDebug(sql_handle);
}
if( flag & PS_DELMEMBER )
{// Remove one party member.
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'",
char_db, party_id, p->member[index].account_id, p->member[index].char_id) )
Sql_ShowDebug(sql_handle);
}
#endif //TXT_SQL_CONVERT
if( save_log )
ShowInfo("Party Saved (%d - %s)\n", party_id, p->name);
return 1;
}
#ifndef TXT_SQL_CONVERT
// Read party from mysql
struct party_data *inter_party_fromsql(int party_id)
{
int leader_id = 0;
int leader_char = 0;
struct party_data* p;
struct party_member* m;
char* data;
size_t len;
int i;
#ifdef NOISY
ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id);
#endif
if( party_id <= 0 )
return NULL;
//Load from memory
p = idb_get(party_db_, party_id);
if( p != NULL )
return p;
p = party_pt;
memset(p, 0, sizeof(struct party_data));
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) )
{
Sql_ShowDebug(sql_handle);
return NULL;
}
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
return NULL;
p->party.party_id = party_id;
Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH));
Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0);
Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data);
Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data);
Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data);
Sql_FreeResult(sql_handle);
// Load members
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) )
{
Sql_ShowDebug(sql_handle);
return NULL;
}
for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
{
m = &p->party.member[i];
Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data);
Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data);
Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH));
Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data);
Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data);
Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0);
Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data);
m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0);
}
Sql_FreeResult(sql_handle);
if( save_log )
ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name);
//Add party to memory.
CREATE(p, struct party_data, 1);
memcpy(p, party_pt, sizeof(struct party_data));
//init state
int_party_calc_state(p);
idb_put(party_db_, party_id, p);
return p;
}
int inter_party_sql_init(void)
{
//memory alloc
party_db_ = idb_alloc(DB_OPT_RELEASE_DATA);
party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1);
if (!party_pt) {
ShowFatalError("inter_party_sql_init: Out of Memory!\n");
exit(EXIT_FAILURE);
}
/* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex]
ShowStatus("cleaning party table...\n");
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL",
party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) )
Sql_ShowDebug(sql_handle);
*/
return 0;
}
void inter_party_sql_final(void)
{
party_db_->destroy(party_db_, NULL);
aFree(party_pt);
return;
}
// Search for the party according to its name
struct party_data* search_partyname(char* str)
{
char esc_name[NAME_LENGTH*2+1];
char* data;
struct party_data* p = NULL;
Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH));
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) )
Sql_ShowDebug(sql_handle);
else if( SQL_SUCCESS == Sql_NextRow(sql_handle) )
{
Sql_GetData(sql_handle, 0, &data, NULL);
p = inter_party_fromsql(atoi(data));
}
Sql_FreeResult(sql_handle);
return p;
}
// Returns whether this party can keep having exp share or not.
int party_check_exp_share(struct party_data *p)
{
return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level);
}
// Is there any member in the party?
int party_check_empty(struct party_data *p)
{
int i;
if (p==NULL||p->party.party_id==0) return 1;
for(i=0;i<MAX_PARTY && !p->party.member[i].account_id;i++);
if (i < MAX_PARTY) return 0;
// If there is no member, then break the party
mapif_party_broken(p->party.party_id,0);
inter_party_tosql(&p->party, PS_BREAK, 0);
return 1;
}
// Check if a member is in two party, not necessary :)
int party_check_conflict(int party_id,int account_id,int char_id)
{
return 0;
}
//-------------------------------------------------------------------
// map server<65>ւ̒ʐM
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><EFBFBD>”<EFBFBD>
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("int_party: Party created (%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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD>񌩂‚<F18CA982><C282>
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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>܂Ƃߑ<C682><DF91><EFBFBD>
int mapif_party_info(int fd,struct party *p)
{
unsigned char buf[5+sizeof(struct party)];
WBUFW(buf,0)=0x3821;
WBUFW(buf,2)=4+sizeof(struct party);
memcpy(buf+4,p,sizeof(struct party));
if(fd<0)
mapif_sendall(buf,WBUFW(buf,2));
else
mapif_send(fd,buf,WBUFW(buf,2));
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD>lj<EFBFBD><C789>”<EFBFBD>
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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>ݒ<EFBFBD><DD92>ύX<CF8D>ʒm
int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag)
{
unsigned char buf[16];
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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>E<EFBFBD>ޒʒ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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>}<7D>b<EFBFBD>v<EFBFBD>X<EFBFBD>V<EFBFBD>ʒ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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD>U<EFBFBD>ʒm
int mapif_party_broken(int party_id,int flag)
{
unsigned char buf[16];
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;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd)
{
unsigned char buf[512];
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<65><72><EFBFBD><EFBFBD><EFBFBD>̒ʐM
// Create Party
int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader)
{
struct party_data *p;
int i;
if( (p=search_partyname(name))!=NULL){
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= aCalloc(1, sizeof(struct party_data));
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;
p->party.member[0].online=1;
p->party.party_id=-1;//New party.
if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) {
//Add party to db
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);
} else { //Failed to create party.
aFree(p);
mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
}
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>v<EFBFBD><76>
int mapif_parse_PartyInfo(int fd,int party_id)
{
struct party_data *p;
p = inter_party_fromsql(party_id);
if (p)
mapif_party_info(fd,&p->party);
else
mapif_party_noinfo(fd,party_id);
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>lj<EFBFBD><C789>v<EFBFBD><76>
int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member)
{
struct party_data *p;
int i;
p = inter_party_fromsql(party_id);
if( p == NULL || p->size == MAX_PARTY ) {
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1);
return 0;
}
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 );
if( i == MAX_PARTY )
{// Party full
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1);
return 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);
inter_party_tosql(&p->party, PS_ADDMEMBER, i);
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>[<5B>ݒ<EFBFBD><DD92>ύX<CF8D>v<EFBFBD><76>
int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item)
{
struct party_data *p;
int flag = 0;
p = inter_party_fromsql(party_id);
if(!p)
return 0;
p->party.exp=exp;
if( exp && !party_check_exp_share(p) ){
flag|=0x01;
p->party.exp=0;
}
p->party.item = item&0x3; //Filter out invalid values.
mapif_party_optionchanged(fd,&p->party,account_id,flag);
inter_party_tosql(&p->party, PS_BASIC, 0);
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>E<EFBFBD>ޗv<DE97><76>
int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
{
struct party_data *p;
int i,j=-1;
p = inter_party_fromsql(party_id);
if( p == NULL )
{// Party does not exists?
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) )
Sql_ShowDebug(sql_handle);
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) {
break;
}
}
if (i >= MAX_PARTY)
return 0; //Member not found?
mapif_party_leaved(party_id, account_id, char_id);
if (p->party.member[i].leader){
p->party.member[i].account_id = 0;
for (j = 0; j < MAX_PARTY; j++) {
if (!p->party.member[j].account_id)
continue;
mapif_party_leaved(party_id, p->party.member[j].account_id, p->party.member[j].char_id);
p->party.member[j].account_id = 0;
}
//Party gets deleted on the check_empty call below.
} else {
inter_party_tosql(&p->party,PS_DELMEMBER,i);
j = 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 (j == p->min_lv || j == p->max_lv || p->family)
{
if(p->family) p->family = 0; //Family state broken.
int_party_check_lv(p);
}
}
if (party_check_empty(p) == 0)
mapif_party_info(-1,&p->party);
return 0;
}
// When member goes to other map or levels up.
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 = inter_party_fromsql(party_id);
if (p == NULL)
return 0;
for(i = 0; i < MAX_PARTY &&
(p->party.member[i].account_id != account_id ||
p->party.member[i].char_id != char_id); i++);
if (i == MAX_PARTY) return 0;
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);
}
//Send online/offline update.
mapif_party_membermoved(&p->party, i);
}
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;
//There is no need to send level update to map servers
//since they do nothing with it.
}
if (p->party.member[i].map != map) {
p->party.member[i].map = map;
mapif_party_membermoved(&p->party, i);
}
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD>U<EFBFBD>v<EFBFBD><76>
int mapif_parse_BreakParty(int fd,int party_id)
{
struct party_data *p;
p = inter_party_fromsql(party_id);
if(!p)
return 0;
inter_party_tosql(&p->party,PS_BREAK,0);
mapif_party_broken(fd,party_id);
return 0;
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD><42><EFBFBD>b<EFBFBD>Z<EFBFBD>[<5B>W<EFBFBD><57><EFBFBD>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);
}
// <20>p<EFBFBD>[<5B>e<EFBFBD>B<EFBFBD>`<60>F<EFBFBD>b<EFBFBD>N<EFBFBD>v<EFBFBD><76>
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 = inter_party_fromsql(party_id);
if(!p)
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;
inter_party_tosql(&p->party,PS_LEADER, i);
}
}
return 1;
}
// map server <20><><EFBFBD><EFBFBD><EFBFBD>̒ʐM
// <20>E<EFBFBD>P<EFBFBD>p<EFBFBD>P<EFBFBD>b<EFBFBD>g<EFBFBD>̂݉<CC82><DD89>͂<EFBFBD><CD82><EFBFBD><E982B1>
// <20>E<EFBFBD>p<EFBFBD>P<EFBFBD>b<EFBFBD>g<EFBFBD><67><EFBFBD>f<EFBFBD>[<5B>^<5E><>inter.c<>ɃZ<C983>b<EFBFBD>g<EFBFBD><67><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// <20>E<EFBFBD>p<EFBFBD>P<EFBFBD>b<EFBFBD>g<EFBFBD><67><EFBFBD>`<60>F<EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>ARFIFOSKIP<49>͌Ăяo<D18F><6F><EFBFBD><EFBFBD><EFBFBD>ōs<C58D><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂ōs<C58D><73><EFBFBD>Ă͂Ȃ<CD82><C882>Ȃ<EFBFBD>
// <20>E<EFBFBD>G<EFBFBD><47><EFBFBD>[<5B>Ȃ<EFBFBD>0(false)<29>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>łȂ<C582><C882>Ȃ<EFBFBD>1(true)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>΂Ȃ<CE82><C882>Ȃ<EFBFBD>
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;
}
// <20>T<EFBFBD>[<5B>o<EFBFBD>[<5B><><EFBFBD><EFBFBD><EFBFBD>E<EFBFBD>ޗv<DE97><76><EFBFBD>i<EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD>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);
}
int inter_party_CharOnline(int char_id, int party_id)
{
struct party_data* p;
int i;
if( party_id == -1 )
{// Get party_id from the database
char* data;
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) )
{
Sql_ShowDebug(sql_handle);
return 0;
}
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
return 0; //Eh? No party?
Sql_GetData(sql_handle, 0, &data, NULL);
party_id = atoi(data);
Sql_FreeResult(sql_handle);
}
if (party_id == 0)
return 0; //No party...
p = inter_party_fromsql(party_id);
if(!p) {
ShowError("Character %d's party %d not found!\n", char_id, party_id);
return 0;
}
//Set member online
for(i=0; i<MAX_PARTY; i++) {
if (p->party.member[i].char_id == char_id) {
if (!p->party.member[i].online) {
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 1;
}
int inter_party_CharOffline(int char_id, int party_id) {
struct party_data *p=NULL;
int i;
if( party_id == -1 )
{// Get guild_id from the database
char* data;
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) )
{
Sql_ShowDebug(sql_handle);
return 0;
}
if( SQL_SUCCESS != Sql_NextRow(sql_handle) )
return 0; //Eh? No party?
Sql_GetData(sql_handle, 0, &data, NULL);
party_id = atoi(data);
Sql_FreeResult(sql_handle);
}
if (party_id == 0)
return 0; //No party...
//Character has a party, set character offline and check if they were the only member online
if ((p = inter_party_fromsql(party_id)) == NULL)
return 0;
//Set member offline
for(i=0; i< MAX_PARTY; i++) {
if(p->party.member[i].char_id == char_id)
{
p->party.member[i].online = 0;
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;
}
}
if(!p->party.count)
//Parties don't have any data that needs be saved at this point... so just remove it from memory.
idb_remove(party_db_, party_id);
return 1;
}
#endif //TXT_SQL_CONVERT