summaryrefslogtreecommitdiff
path: root/src/map/party.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/party.c')
-rw-r--r--src/map/party.c274
1 files changed, 178 insertions, 96 deletions
diff --git a/src/map/party.c b/src/map/party.c
index 88f53bcb0..a8a524046 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -28,8 +28,8 @@
#include <string.h>
-static DBMap* party_db; // int party_id -> struct party_data*
-static DBMap* party_booking_db; // Party Booking [Spiria]
+static DBMap* party_db; // int party_id -> struct party_data* (releases data)
+static DBMap* party_booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria]
static unsigned long party_booking_nextid = 1;
int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
@@ -38,18 +38,36 @@ int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
* Fills the given party_member structure according to the sd provided.
* Used when creating/adding people to a party. [Skotlex]
*------------------------------------------*/
-static void party_fill_member(struct party_member *member, struct map_session_data *sd)
+static void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader)
{
member->account_id = sd->status.account_id;
member->char_id = sd->status.char_id;
- memcpy(member->name, sd->status.name, NAME_LENGTH);
+ safestrncpy(member->name, sd->status.name, NAME_LENGTH);
member->class_ = sd->status.class_;
member->map = sd->mapindex;
member->lv = sd->status.base_level;
member->online = 1;
- member->leader = 0;
+ member->leader = leader;
}
+
+/// Get the member_id of a party member.
+/// Return -1 if not in party.
+int party_getmemberid(struct party_data* p, struct map_session_data* sd)
+{
+ int member_id;
+ nullpo_retr(-1, p);
+ if( sd == NULL )
+ return -1;// no player
+ ARR_FIND(0, MAX_PARTY, member_id,
+ p->party.member[member_id].account_id == sd->status.account_id &&
+ p->party.member[member_id].char_id == sd->status.char_id);
+ if( member_id == MAX_PARTY )
+ return -1;// not found
+ return member_id;
+}
+
+
/*==========================================
* Request an available sd of this party
*------------------------------------------*/
@@ -72,6 +90,8 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id)
if (!(sd && sd->status.char_id == char_id))
return NULL;
+ if( sd->status.party_id == 0 )
+ sd->status.party_id = party_id;// auto-join if not in a party
if (sd->status.party_id != party_id)
{ //If player belongs to a different party, kick him out.
intif_party_leave(party_id,account_id,char_id);
@@ -143,8 +163,7 @@ int party_create(struct map_session_data *sd,char *name,int item,int item2)
sd->party_creating = true;
- party_fill_member(&leader, sd);
- leader.leader = 1;
+ party_fill_member(&leader, sd, 1);
intif_create_party(&leader,name,item,item2);
return 0;
@@ -175,63 +194,26 @@ void party_created(int account_id,int char_id,int fail,int party_id,char *name)
}
-int party_request_info(int party_id)
+int party_request_info(int party_id, int char_id)
{
- return intif_request_partyinfo(party_id);
+ return intif_request_partyinfo(party_id, char_id);
}
-/// Checks if each char having a party actually belongs to that party.
-/// If check fails, the char gets marked as 'not in a party'.
-int party_check_member(struct party *p)
+/// Invoked (from char-server) when the party info is not found.
+int party_recv_noinfo(int party_id, int char_id)
{
- int i;
- struct map_session_data *sd;
- struct s_mapiterator* iter;
-
- nullpo_ret(p);
+ struct map_session_data* sd;
- iter = mapit_getallusers();
- for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
+ party_broken(party_id);
+ if( char_id != 0 )// requester
{
- if( sd->status.party_id != p->party_id )
- continue;
-
- ARR_FIND( 0, MAX_PARTY, i, p->member[i].account_id == sd->status.account_id && p->member[i].char_id == sd->status.char_id );
- if( i == MAX_PARTY )
- {
- ShowWarning("party_check_member: '%s' (acc:%d) is not member of party '%s' (id:%d)\n",sd->status.name,sd->status.account_id,p->name,p->party_id);
+ sd = map_charid2sd(char_id);
+ if( sd && sd->status.party_id == party_id )
sd->status.party_id = 0;
- }
- }
- mapit_free(iter);
-
- return 0;
-}
-
-/// Marks all chars belonging to this party as 'not in a party'.
-int party_recv_noinfo(int party_id)
-{
- struct map_session_data *sd;
- struct s_mapiterator* iter;
-
- iter = mapit_getallusers();
- for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
- {
- if( sd->status.party_id == party_id )
- sd->status.party_id = 0; // erase party
}
- mapit_free(iter);
-
return 0;
}
-static void* create_party(DBKey key, va_list args)
-{
- struct party_data *p;
- p=(struct party_data *)aCalloc(1,sizeof(struct party_data));
- return p;
-}
-
static void party_check_state(struct party_data *p)
{
int i;
@@ -259,42 +241,92 @@ static void party_check_state(struct party_data *p)
}
}
-int party_recv_info(struct party *sp)
+int party_recv_info(struct party* sp, int char_id)
{
- struct party_data *p;
+ struct party_data* p;
+ struct party_member* member;
+ struct map_session_data* sd;
+ int removed[MAX_PARTY];// member_id in old data
+ int removed_count = 0;
+ int added[MAX_PARTY];// member_id in new data
+ int added_count = 0;
int i;
- bool party_new = false;
+ int member_id;
nullpo_ret(sp);
- p = (struct party_data*)idb_ensure(party_db, sp->party_id, create_party);
- if (!p->party.party_id) //party just received.
+ p = (struct party_data*)idb_get(party_db, sp->party_id);
+ if( p != NULL )// diff members
+ {
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ {
+ member = &p->party.member[member_id];
+ if( member->char_id == 0 )
+ continue;// empty
+ ARR_FIND(0, MAX_PARTY, i,
+ sp->member[i].account_id == member->account_id &&
+ sp->member[i].char_id == member->char_id);
+ if( i == MAX_PARTY )
+ removed[removed_count++] = member_id;
+ }
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ {
+ member = &sp->member[member_id];
+ if( member->char_id == 0 )
+ continue;// empty
+ ARR_FIND(0, MAX_PARTY, i,
+ p->party.member[i].account_id == member->account_id &&
+ p->party.member[i].char_id == member->char_id);
+ if( i == MAX_PARTY )
+ added[added_count++] = member_id;
+ }
+ }
+ else
+ {
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ if( sp->member[member_id].char_id != 0 )
+ added[added_count++] = member_id;
+ CREATE(p, struct party_data, 1);
+ idb_put(party_db, sp->party_id, p);
+ }
+ while( removed_count > 0 )// no longer in party
{
- party_new = true;
- party_check_member(sp);
+ member_id = removed[--removed_count];
+ sd = p->data[member_id].sd;
+ if( sd == NULL )
+ continue;// not online
+ party_member_withdraw(sp->party_id, sd->status.account_id, sd->status.char_id);
}
- memcpy(&p->party,sp,sizeof(struct party));
+ memcpy(&p->party, sp, sizeof(struct party));
memset(&p->state, 0, sizeof(p->state));
memset(&p->data, 0, sizeof(p->data));
- for(i=0;i<MAX_PARTY;i++){
- if (!p->party.member[i].account_id)
- continue;
- p->data[i].sd = party_sd_check(p->party.party_id, p->party.member[i].account_id, p->party.member[i].char_id);
+ for( member_id = 0; member_id < MAX_PARTY; member_id++ )
+ {
+ member = &p->party.member[member_id];
+ if ( member->char_id == 0 )
+ continue;// empty
+ p->data[member_id].sd = party_sd_check(sp->party_id, member->account_id, member->char_id);
}
party_check_state(p);
- if (party_new) {
- //Send party data to all players.
- struct map_session_data *sd;
- for(i=0;i<MAX_PARTY;i++){
- sd = p->data[i].sd;
- if(!sd) continue;
- clif_charnameupdate(sd); //Update other people's display. [Skotlex]
- clif_party_member_info(p,sd);
- clif_party_option(p,sd,0x100);
- clif_party_info(p,NULL);
- }
+ while( added_count > 0 )// new in party
+ {
+ member_id = added[--added_count];
+ sd = p->data[member_id].sd;
+ if( sd == NULL )
+ continue;// not online
+ clif_charnameupdate(sd); //Update other people's display. [Skotlex]
+ clif_party_member_info(p,sd);
+ clif_party_option(p,sd,0x100);
+ clif_party_info(p,NULL);
+ if( p->instance_id != 0 )
+ clif_instance_join(sd->fd, p->instance_id);
+ }
+ if( char_id != 0 )// requester
+ {
+ sd = map_charid2sd(char_id);
+ if( sd && sd->status.party_id == sp->party_id && party_getmemberid(p,sd) == -1 )
+ sd->status.party_id = 0;// was not in the party
}
-
return 0;
}
@@ -306,8 +338,8 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
nullpo_ret(sd);
if( ( p = party_search(sd->status.party_id) ) == NULL )
return 0;
- if( tsd == NULL) { //TODO: Find the correct reply packet.
- clif_displaymessage(sd->fd, msg_txt(3));
+ if( tsd == NULL) {
+ clif_party_inviteack(sd, "", 7);
return 0;
}
@@ -385,7 +417,7 @@ void party_reply_invite(struct map_session_data *sd,int party_id,int flag)
if( flag == 1 && !sd->party_creating && !sd->party_joining )
{// accepted and allowed
sd->party_joining = true;
- party_fill_member(&member, sd);
+ party_fill_member(&member, sd, 0);
intif_party_addmember(sd->party_invite, &member);
}
else
@@ -407,7 +439,7 @@ void party_member_joined(struct map_session_data *sd)
int i;
if (!p)
{
- party_request_info(sd->status.party_id);
+ party_request_info(sd->status.party_id, sd->status.char_id);
return;
}
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == sd->status.account_id && p->party.member[i].char_id == sd->status.char_id );
@@ -456,14 +488,6 @@ int party_member_added(int party_id,int account_id,int char_id, int flag)
sd->status.party_id = party_id;
- ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 );
- if (i < MAX_PARTY) {
- //TODO: This is a hack to allow the following clif calls to send the data to the new player.
- //The correct player data is set when party_recv_info arrives soon afterwards.
- party_fill_member(&p->party.member[i], sd);
- p->data[i].sd = sd;
- }
-
clif_party_member_info(p,sd);
clif_party_option(p,sd,0x100);
clif_party_info(p,sd);
@@ -542,7 +566,7 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
if( i < MAX_PARTY )
{
- clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x00);
+ clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x0);
memset(&p->party.member[i], 0, sizeof(p->party.member[0]));
memset(&p->data[i], 0, sizeof(p->data[0]));
p->party.count--;
@@ -849,11 +873,16 @@ int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
for( p = (struct party_data*)iter->first(iter,NULL); iter->exists(iter); p = (struct party_data*)iter->next(iter,NULL) )
{
int i;
+
+ if( !p->party.count )
+ {// no online party members so do not iterate
+ continue;
+ }
+
// for each member of this party,
for( i = 0; i < MAX_PARTY; i++ )
{
- //struct map_session_data* sd = p->data[i].sd;
- struct map_session_data* sd = map_charid2sd(p->party.member[i].char_id); //temporary crashfix
+ struct map_session_data* sd = p->data[i].sd;
if( !sd ) continue;
if( p->data[i].x != sd->bl.x || p->data[i].y != sd->bl.y )
@@ -888,13 +917,64 @@ int party_send_xy_clear(struct party_data *p)
}
return 0;
}
-
+#if RRMODE
+/**
+ * Renewal Drop Earning Modifier
+ **/
+int party_renewal_drop_mod(int diff) {
+ if( diff >= -10 && diff <= 5 )
+ return 100;//no change.
+ if( diff > 0 ) {
+ if( diff > 5 && diff < 10 )
+ return 90;
+ if( diff > 9 && diff < 15 )
+ return 75;
+ if( diff > 14 && diff < 30 )
+ return 60;
+ } else {
+ if( diff <= -10 && diff <= -14 )
+ return 75;//75%
+ }
+ //other chases: 50%
+ return 50;
+}
+/**
+ * Renewal Experience Earning Mode
+ **/
+void party_renewal_exp_mod(unsigned int *base_exp, unsigned int *job_exp, int lvl, int moblvl) {
+ int diff = lvl - moblvl, boost = 0;
+ //-2 ~ +5: 100%
+ if( diff >= -2 && diff <= 5 )
+ return;//we don't change anything, it's 100% boost
+ //-3 ~ -10: +5% boost for each
+ if( diff >= -10 && diff <= -3 )
+ boost = 100 + (( -diff * 5 ) - 15 );
+ // 40% boost if difference is <= -10
+ else if ( diff <= -10 )
+ boost = 40;
+ else {
+ boost = ( diff > 5 && diff < 11 ) ? 95 :
+ ( diff > 10 && diff < 16 ) ? 90 :
+ ( diff > 15 && diff < 21 ) ? 85 :
+ ( diff > 20 && diff < 26 ) ? 60 :
+ ( diff > 25 && diff < 31 ) ? 35 :
+ 10;
+ }
+ if( *base_exp )
+ *base_exp = (unsigned int)cap_value(*base_exp * boost / 100, 1, UINT_MAX);
+ if( *job_exp )
+ *job_exp = (unsigned int)cap_value(*job_exp * boost / 100, 1, UINT_MAX);
+ return;
+}
+#endif
// exp share and added zeny share [Valaris]
int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny)
{
struct map_session_data* sd[MAX_PARTY];
unsigned int i, c;
-
+#if RRMODE
+ int src_lvl = status_get_lv(src);
+#endif
nullpo_ret(p);
// count the number of players eligible for exp sharing
@@ -921,8 +1001,10 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b
zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX);
}
- for (i = 0; i < c; i++)
- {
+ for (i = 0; i < c; i++) {
+#if RRMODE
+ party_renewal_exp_mod(&base_exp,&job_exp,sd[i]->status.base_level,src_lvl);
+#endif
pc_gainexp(sd[i], src, base_exp, job_exp, false);
if (zeny) // zeny from mobs [Valaris]
pc_getzeny(sd[i],zeny);