party.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "party.hpp"
  4. #include <stdlib.h>
  5. #include "../common/cbasetypes.hpp"
  6. #include "../common/malloc.hpp"
  7. #include "../common/nullpo.hpp"
  8. #include "../common/random.hpp"
  9. #include "../common/showmsg.hpp"
  10. #include "../common/socket.hpp" // last_tick
  11. #include "../common/strlib.hpp"
  12. #include "../common/timer.hpp"
  13. #include "../common/utils.hpp"
  14. #include "achievement.hpp"
  15. #include "atcommand.hpp" //msg_txt()
  16. #include "battle.hpp"
  17. #include "clif.hpp"
  18. #include "instance.hpp"
  19. #include "intif.hpp"
  20. #include "log.hpp"
  21. #include "mapreg.hpp"
  22. #include "mob.hpp"
  23. #include "pc.hpp"
  24. #include "pc_groups.hpp"
  25. #include "trade.hpp"
  26. static DBMap* party_db; // int party_id -> struct party_data* (releases data)
  27. static DBMap* party_booking_db; // uint32 char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria]
  28. static unsigned long party_booking_nextid = 1;
  29. TIMER_FUNC(party_send_xy_timer);
  30. int party_create_byscript;
  31. /*==========================================
  32. * Fills the given party_member structure according to the sd provided.
  33. * Used when creating/adding people to a party. [Skotlex]
  34. *------------------------------------------*/
  35. static void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader)
  36. {
  37. member->account_id = sd->status.account_id;
  38. member->char_id = sd->status.char_id;
  39. safestrncpy(member->name, sd->status.name, NAME_LENGTH);
  40. member->class_ = sd->status.class_;
  41. member->map = sd->mapindex;
  42. member->lv = sd->status.base_level;
  43. member->online = 1;
  44. member->leader = leader;
  45. }
  46. /// Get the member_id of a party member.
  47. /// Return -1 if not in party.
  48. int party_getmemberid(struct party_data* p, struct map_session_data* sd)
  49. {
  50. int member_id;
  51. nullpo_retr(-1, p);
  52. if( sd == NULL )
  53. return -1;// no player
  54. ARR_FIND(0, MAX_PARTY, member_id,
  55. p->party.member[member_id].account_id == sd->status.account_id &&
  56. p->party.member[member_id].char_id == sd->status.char_id);
  57. if( member_id == MAX_PARTY )
  58. return -1;// not found
  59. return member_id;
  60. }
  61. /*==========================================
  62. * Request an available sd of this party
  63. *------------------------------------------*/
  64. struct map_session_data* party_getavailablesd(struct party_data *p)
  65. {
  66. int i;
  67. nullpo_retr(NULL, p);
  68. ARR_FIND(0, MAX_PARTY, i, p->data[i].sd != NULL);
  69. return( i < MAX_PARTY ) ? p->data[i].sd : NULL;
  70. }
  71. /*==========================================
  72. * Retrieves and validates the sd pointer for this party member [Skotlex]
  73. *------------------------------------------*/
  74. static TBL_PC* party_sd_check(int party_id, uint32 account_id, uint32 char_id)
  75. {
  76. TBL_PC* sd = map_id2sd(account_id);
  77. if (!(sd && sd->status.char_id == char_id))
  78. return NULL;
  79. if( sd->status.party_id == 0 )
  80. sd->status.party_id = party_id;// auto-join if not in a party
  81. if (sd->status.party_id != party_id)
  82. { //If player belongs to a different party, kick him out.
  83. intif_party_leave(party_id,account_id,char_id,sd->status.name,PARTY_MEMBER_WITHDRAW_LEAVE);
  84. return NULL;
  85. }
  86. return sd;
  87. }
  88. /*==========================================
  89. * Destructor
  90. * Called in map shutdown, cleanup var
  91. *------------------------------------------*/
  92. void do_final_party(void)
  93. {
  94. party_db->destroy(party_db,NULL);
  95. party_booking_db->destroy(party_booking_db,NULL); // Party Booking [Spiria]
  96. }
  97. // Constructor, init vars
  98. void do_init_party(void)
  99. {
  100. party_db = idb_alloc(DB_OPT_RELEASE_DATA);
  101. party_booking_db = idb_alloc(DB_OPT_RELEASE_DATA); // Party Booking [Spiria]
  102. add_timer_func_list(party_send_xy_timer, "party_send_xy_timer");
  103. add_timer_interval(gettick()+battle_config.party_update_interval, party_send_xy_timer, 0, 0, battle_config.party_update_interval);
  104. }
  105. /// Party data lookup using party id.
  106. struct party_data* party_search(int party_id)
  107. {
  108. if(!party_id)
  109. return NULL;
  110. return (struct party_data*)idb_get(party_db,party_id);
  111. }
  112. /// Party data lookup using party name.
  113. struct party_data* party_searchname(const char* str)
  114. {
  115. struct party_data* p;
  116. DBIterator *iter = db_iterator(party_db);
  117. for( p = (struct party_data*)dbi_first(iter); dbi_exists(iter); p = (struct party_data*)dbi_next(iter) ) {
  118. if( strncmpi(p->party.name,str,NAME_LENGTH) == 0 )
  119. break;
  120. }
  121. dbi_destroy(iter);
  122. return p;
  123. }
  124. int party_create(struct map_session_data *sd,char *name,int item,int item2)
  125. {
  126. struct party_member leader;
  127. char tname[NAME_LENGTH];
  128. safestrncpy(tname, name, NAME_LENGTH);
  129. trim(tname);
  130. if( !tname[0] ) // empty name
  131. return 0;
  132. if( sd->status.party_id > 0 || sd->party_joining || sd->party_creating ) { // already associated with a party
  133. clif_party_created(sd,2);
  134. return -2;
  135. }
  136. sd->party_creating = true;
  137. party_fill_member(&leader, sd, 1);
  138. intif_create_party(&leader,name,item,item2);
  139. return 1;
  140. }
  141. void party_created(uint32 account_id,uint32 char_id,int fail,int party_id,char *name)
  142. {
  143. struct map_session_data *sd;
  144. sd = map_id2sd(account_id);
  145. if (!sd || sd->status.char_id != char_id || !sd->party_creating ) { // Character logged off before creation ack?
  146. if (!fail) // break up party since player could not be added to it.
  147. intif_party_leave(party_id,account_id,char_id,"",PARTY_MEMBER_WITHDRAW_LEAVE);
  148. return;
  149. }
  150. sd->party_creating = false;
  151. if( !fail ) {
  152. sd->status.party_id = party_id;
  153. clif_party_created(sd,0); // Success message
  154. achievement_update_objective(sd, AG_PARTY, 1, 1);
  155. // We don't do any further work here because the char-server sends a party info packet right after creating the party
  156. if(party_create_byscript) { // returns party id in $@party_create_id if party is created by script
  157. mapreg_setreg(add_str("$@party_create_id"),party_id);
  158. party_create_byscript = 0;
  159. }
  160. } else
  161. clif_party_created(sd,1); // "party name already exists"
  162. }
  163. int party_request_info(int party_id, uint32 char_id)
  164. {
  165. return intif_request_partyinfo(party_id, char_id);
  166. }
  167. /**
  168. * Close trade window if party member is kicked when trade a party bound item
  169. * @param sd
  170. **/
  171. static void party_trade_bound_cancel(struct map_session_data *sd) {
  172. #ifdef BOUND_ITEMS
  173. nullpo_retv(sd);
  174. if (sd->state.isBoundTrading&(1<<BOUND_PARTY))
  175. trade_tradecancel(sd);
  176. #else
  177. ;
  178. #endif
  179. }
  180. /// Invoked (from char-server) when the party info is not found.
  181. int party_recv_noinfo(int party_id, uint32 char_id)
  182. {
  183. party_broken(party_id);
  184. if( char_id != 0 ) { // requester
  185. struct map_session_data* sd;
  186. sd = map_charid2sd(char_id);
  187. if( sd && sd->status.party_id == party_id )
  188. sd->status.party_id = 0;
  189. }
  190. return 0;
  191. }
  192. static void party_check_state(struct party_data *p)
  193. {
  194. int i;
  195. memset(&p->state, 0, sizeof(p->state));
  196. for (i = 0; i < MAX_PARTY; i ++) {
  197. if (!p->party.member[i].online)
  198. continue; //Those not online shouldn't aport to skill usage and all that.
  199. switch (p->party.member[i].class_) {
  200. case JOB_MONK:
  201. case JOB_BABY_MONK:
  202. case JOB_CHAMPION:
  203. case JOB_SURA:
  204. case JOB_SURA_T:
  205. case JOB_BABY_SURA:
  206. p->state.monk = 1;
  207. break;
  208. case JOB_STAR_GLADIATOR:
  209. case JOB_BABY_STAR_GLADIATOR:
  210. case JOB_STAR_EMPEROR:
  211. case JOB_BABY_STAR_EMPEROR:
  212. p->state.sg = 1;
  213. break;
  214. case JOB_SUPER_NOVICE:
  215. case JOB_SUPER_BABY:
  216. case JOB_SUPER_NOVICE_E:
  217. case JOB_SUPER_BABY_E:
  218. p->state.snovice = 1;
  219. break;
  220. case JOB_TAEKWON:
  221. case JOB_BABY_TAEKWON:
  222. p->state.tk = 1;
  223. break;
  224. }
  225. }
  226. }
  227. int party_recv_info(struct party* sp, uint32 char_id)
  228. {
  229. struct party_data* p;
  230. struct party_member* member;
  231. struct map_session_data* sd;
  232. int removed[MAX_PARTY];// member_id in old data
  233. int removed_count = 0;
  234. int added[MAX_PARTY];// member_id in new data
  235. int added_count = 0;
  236. int member_id;
  237. bool rename = false;
  238. nullpo_ret(sp);
  239. p = (struct party_data*)idb_get(party_db, sp->party_id);
  240. if( p != NULL ) { // diff members
  241. int i;
  242. for( member_id = 0; member_id < MAX_PARTY; ++member_id ) {
  243. member = &p->party.member[member_id];
  244. if( member->char_id == 0 )
  245. continue; // empty
  246. ARR_FIND(0, MAX_PARTY, i,
  247. sp->member[i].account_id == member->account_id &&
  248. sp->member[i].char_id == member->char_id);
  249. if( i == MAX_PARTY )
  250. removed[removed_count++] = member_id;
  251. // If the member already existed, compare the old to the (possible) new name
  252. else if( !rename && strcmp(member->name,sp->member[i].name) )
  253. rename = true;
  254. }
  255. for( member_id = 0; member_id < MAX_PARTY; ++member_id ) {
  256. member = &sp->member[member_id];
  257. if( member->char_id == 0 )
  258. continue; // empty
  259. ARR_FIND(0, MAX_PARTY, i,
  260. p->party.member[i].account_id == member->account_id &&
  261. p->party.member[i].char_id == member->char_id);
  262. if( i == MAX_PARTY )
  263. added[added_count++] = member_id;
  264. }
  265. } else {
  266. for( member_id = 0; member_id < MAX_PARTY; ++member_id )
  267. if( sp->member[member_id].char_id != 0 )
  268. added[added_count++] = member_id;
  269. CREATE(p, struct party_data, 1);
  270. idb_put(party_db, sp->party_id, p);
  271. }
  272. while( removed_count > 0 ) { // no longer in party
  273. member_id = removed[--removed_count];
  274. sd = p->data[member_id].sd;
  275. if( sd == NULL )
  276. continue; // not online
  277. party_member_withdraw(sp->party_id, sd->status.account_id, sd->status.char_id, sd->status.name, PARTY_MEMBER_WITHDRAW_LEAVE);
  278. }
  279. memcpy(&p->party, sp, sizeof(struct party));
  280. memset(&p->state, 0, sizeof(p->state));
  281. memset(&p->data, 0, sizeof(p->data));
  282. for( member_id = 0; member_id < MAX_PARTY; member_id++ ) {
  283. member = &p->party.member[member_id];
  284. if ( member->char_id == 0 )
  285. continue;// empty
  286. p->data[member_id].sd = party_sd_check(sp->party_id, member->account_id, member->char_id);
  287. }
  288. party_check_state(p);
  289. while( added_count > 0 ) { // new in party
  290. member_id = added[--added_count];
  291. sd = p->data[member_id].sd;
  292. if( sd == NULL )
  293. continue;// not online
  294. clif_name_area(&sd->bl); //Update other people's display. [Skotlex]
  295. clif_party_member_info(p,sd);
  296. // Only send this on party creation, otherwise it will be sent by party_send_movemap [Lemongrass]
  297. if( sd->party_creating ){
  298. clif_party_option(p,sd,0x100);
  299. }
  300. clif_party_info(p,NULL);
  301. if( p->instance_id != 0 )
  302. instance_reqinfo(sd,p->instance_id);
  303. }
  304. // If a player was renamed, make sure to resend the party information
  305. if( rename ){
  306. clif_party_info(p,NULL);
  307. }
  308. if( char_id != 0 ) { // requester
  309. sd = map_charid2sd(char_id);
  310. if( sd && sd->status.party_id == sp->party_id && party_getmemberid(p,sd) == -1 )
  311. sd->status.party_id = 0;// was not in the party
  312. }
  313. return 0;
  314. }
  315. ///! TODO: Party invitation cross map-server through inter-server, so does with the reply.
  316. int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
  317. {
  318. struct party_data *p;
  319. int i;
  320. nullpo_ret(sd);
  321. if( ( p = party_search(sd->status.party_id) ) == NULL )
  322. return 0;
  323. // confirm if this player is a party leader
  324. ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);
  325. if( i == MAX_PARTY || !p->party.member[i].leader ) {
  326. clif_displaymessage(sd->fd, msg_txt(sd,282));
  327. return 0;
  328. }
  329. if (tsd && battle_config.block_account_in_same_party) {
  330. ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == tsd->status.account_id);
  331. if (i < MAX_PARTY) {
  332. clif_party_invite_reply(sd, tsd->status.name, PARTY_REPLY_DUAL);
  333. return 0;
  334. }
  335. }
  336. // confirm if there is an open slot in the party
  337. ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == 0);
  338. if( i == MAX_PARTY ) {
  339. clif_party_invite_reply(sd, (tsd?tsd->status.name:""), PARTY_REPLY_FULL);
  340. return 0;
  341. }
  342. // confirm whether the account has the ability to invite before checking the player
  343. if( !pc_has_permission(sd, PC_PERM_PARTY) || (tsd && !pc_has_permission(tsd, PC_PERM_PARTY)) ) {
  344. clif_displaymessage(sd->fd, msg_txt(sd,81)); // "Your GM level doesn't authorize you to preform this action on the specified player."
  345. return 0;
  346. }
  347. if( tsd == NULL) {
  348. clif_party_invite_reply(sd, "", PARTY_REPLY_OFFLINE);
  349. return 0;
  350. }
  351. if(!battle_config.invite_request_check) {
  352. if (tsd->guild_invite>0 || tsd->trade_partner || tsd->adopt_invite) {
  353. clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_JOIN_OTHER_PARTY);
  354. return 0;
  355. }
  356. }
  357. if (!tsd->fd) { //You can't invite someone who has already disconnected.
  358. clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_REJECTED);
  359. return 0;
  360. }
  361. if( tsd->status.party_id > 0 || tsd->party_invite > 0 )
  362. {// already associated with a party
  363. clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_JOIN_OTHER_PARTY);
  364. return 0;
  365. }
  366. tsd->party_invite=sd->status.party_id;
  367. tsd->party_invite_account=sd->status.account_id;
  368. clif_party_invite(sd,tsd);
  369. return 1;
  370. }
  371. int party_reply_invite(struct map_session_data *sd,int party_id,int flag)
  372. {
  373. struct map_session_data* tsd;
  374. struct party_member member;
  375. if( sd->party_invite != party_id ) { // forged
  376. sd->party_invite = 0;
  377. sd->party_invite_account = 0;
  378. return 0;
  379. }
  380. // The character is already in a party, possibly left a party invite open and created his own party
  381. if( sd->status.party_id != 0 ){
  382. // On Aegis no rejection packet is sent to the inviting player
  383. sd->party_invite = 0;
  384. sd->party_invite_account = 0;
  385. return 0;
  386. }
  387. tsd = map_id2sd(sd->party_invite_account);
  388. if( flag == 1 && !sd->party_creating && !sd->party_joining ) { // accepted and allowed
  389. sd->party_joining = true;
  390. party_fill_member(&member, sd, 0);
  391. intif_party_addmember(sd->party_invite, &member);
  392. return 1;
  393. } else { // rejected or failure
  394. sd->party_invite = 0;
  395. sd->party_invite_account = 0;
  396. if( tsd != NULL )
  397. clif_party_invite_reply(tsd,sd->status.name,PARTY_REPLY_REJECTED);
  398. }
  399. return 0;
  400. }
  401. //Invoked when a player joins:
  402. //- Loads up party data if not in server
  403. //- Sets up the pointer to him
  404. //- Player must be authed/active and belong to a party before calling this method
  405. void party_member_joined(struct map_session_data *sd)
  406. {
  407. struct party_data* p = party_search(sd->status.party_id);
  408. int i;
  409. if (!p) {
  410. party_request_info(sd->status.party_id, sd->status.char_id);
  411. return;
  412. }
  413. 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 );
  414. if (i < MAX_PARTY) {
  415. p->data[i].sd = sd;
  416. if( p->instance_id )
  417. instance_reqinfo(sd,p->instance_id);
  418. } else
  419. sd->status.party_id = 0; //He does not belongs to the party really?
  420. }
  421. /// Invoked (from char-server) when a new member is added to the party.
  422. /// flag: 0-success, 1-failure
  423. int party_member_added(int party_id,uint32 account_id,uint32 char_id, int flag)
  424. {
  425. struct map_session_data *sd = map_id2sd(account_id),*sd2;
  426. struct party_data *p = party_search(party_id);
  427. int i;
  428. if(sd == NULL || sd->status.char_id != char_id || !sd->party_joining ) {
  429. if (!flag) //Char logged off before being accepted into party.
  430. intif_party_leave(party_id,account_id,char_id,"",PARTY_MEMBER_WITHDRAW_LEAVE);
  431. return 0;
  432. }
  433. sd2 = map_id2sd(sd->party_invite_account);
  434. sd->party_joining = false;
  435. sd->party_invite = 0;
  436. sd->party_invite_account = 0;
  437. if (!p) {
  438. ShowError("party_member_added: party %d not found.\n",party_id);
  439. intif_party_leave(party_id,account_id,char_id,"",PARTY_MEMBER_WITHDRAW_LEAVE);
  440. return 0;
  441. }
  442. if( flag ) { // failed
  443. if( sd2 != NULL )
  444. clif_party_invite_reply(sd2,sd->status.name,PARTY_REPLY_FULL);
  445. return 0;
  446. }
  447. sd->status.party_id = party_id;
  448. clif_party_member_info(p,sd);
  449. clif_party_option(p,sd,0x100);
  450. clif_party_info(p,sd);
  451. if( sd2 != NULL )
  452. clif_party_invite_reply(sd2,sd->status.name,PARTY_REPLY_ACCEPTED);
  453. for( i = 0; i < ARRAYLENGTH(p->data); ++i ) { // hp of the other party members
  454. sd2 = p->data[i].sd;
  455. if( sd2 && sd2->status.account_id != account_id && sd2->status.char_id != char_id )
  456. clif_hpmeter_single(sd->fd, sd2->bl.id, sd2->battle_status.hp, sd2->battle_status.max_hp);
  457. }
  458. clif_party_hp(sd);
  459. clif_party_xy(sd);
  460. clif_name_area(&sd->bl); //Update char name's display [Skotlex]
  461. if( p->instance_id )
  462. instance_reqinfo(sd,p->instance_id);
  463. return 0;
  464. }
  465. /// Party member 'sd' requesting kick of member with <account_id, name>.
  466. int party_removemember(struct map_session_data* sd, uint32 account_id, char* name)
  467. {
  468. struct party_data *p;
  469. int i;
  470. p = party_search(sd->status.party_id);
  471. if( p == NULL )
  472. return 0;
  473. // check the requesting char's party membership
  474. 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 );
  475. if( i == MAX_PARTY )
  476. return 0; // request from someone not in party? o.O
  477. if( !p->party.member[i].leader )
  478. return 0; // only party leader may remove members
  479. ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && strncmp(p->party.member[i].name,name,NAME_LENGTH) == 0 );
  480. if( i == MAX_PARTY )
  481. return 0; // no such char in party
  482. party_trade_bound_cancel(sd);
  483. intif_party_leave(p->party.party_id,account_id,p->party.member[i].char_id,p->party.member[i].name,PARTY_MEMBER_WITHDRAW_EXPEL);
  484. return 1;
  485. }
  486. int party_removemember2(struct map_session_data *sd,uint32 char_id,int party_id)
  487. {
  488. if( sd ) {
  489. if( !sd->status.party_id )
  490. return -3;
  491. party_trade_bound_cancel(sd);
  492. intif_party_leave(sd->status.party_id,sd->status.account_id,sd->status.char_id,sd->status.name,PARTY_MEMBER_WITHDRAW_EXPEL);
  493. return 1;
  494. } else {
  495. int i;
  496. struct party_data *p;
  497. if( !(p = party_search(party_id)) )
  498. return -2;
  499. ARR_FIND(0,MAX_PARTY,i,p->party.member[i].char_id == char_id );
  500. if( i >= MAX_PARTY )
  501. return -1;
  502. intif_party_leave(party_id,p->party.member[i].account_id,char_id,p->party.member[i].name,PARTY_MEMBER_WITHDRAW_EXPEL);
  503. return 1;
  504. }
  505. }
  506. /// Party member 'sd' requesting exit from party.
  507. int party_leave(struct map_session_data *sd)
  508. {
  509. struct party_data *p;
  510. int i;
  511. p = party_search(sd->status.party_id);
  512. if( p == NULL )
  513. return 0;
  514. 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 );
  515. if( i == MAX_PARTY )
  516. return 0;
  517. party_trade_bound_cancel(sd);
  518. intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id,sd->status.name,PARTY_MEMBER_WITHDRAW_LEAVE);
  519. return 1;
  520. }
  521. /// Invoked (from char-server) when a party member leaves the party.
  522. int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id, char *name, enum e_party_member_withdraw type)
  523. {
  524. struct map_session_data* sd = map_charid2sd(char_id);
  525. struct party_data* p = party_search(party_id);
  526. if( p ) {
  527. int i;
  528. clif_party_withdraw(party_getavailablesd(p), account_id, name, type, PARTY);
  529. ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
  530. if( i < MAX_PARTY ) {
  531. memset(&p->party.member[i], 0, sizeof(p->party.member[0]));
  532. memset(&p->data[i], 0, sizeof(p->data[0]));
  533. p->party.count--;
  534. party_check_state(p);
  535. }
  536. }
  537. if( sd && sd->status.party_id == party_id ) {
  538. #ifdef BOUND_ITEMS
  539. int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion
  540. int j,i;
  541. party_trade_bound_cancel(sd);
  542. j = pc_bound_chk(sd,BOUND_PARTY,idxlist);
  543. for(i = 0; i < j; i++)
  544. pc_delitem(sd,idxlist[i],sd->inventory.u.items_inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
  545. #endif
  546. sd->status.party_id = 0;
  547. clif_name_area(&sd->bl); //Update name display [Skotlex]
  548. //TODO: hp bars should be cleared too
  549. if( p->instance_id ) {
  550. int16 m = sd->bl.m;
  551. if( map[m].instance_id ) { // User was on the instance map
  552. if( map[m].save.map )
  553. pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT);
  554. else
  555. pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
  556. }
  557. }
  558. }
  559. return 0;
  560. }
  561. /// Invoked (from char-server) when a party is disbanded.
  562. int party_broken(int party_id)
  563. {
  564. struct party_data* p;
  565. int i;
  566. p = party_search(party_id);
  567. if( p == NULL )
  568. return 0;
  569. if( p->instance_id )
  570. instance_destroy( p->instance_id );
  571. for( i = 0; i < MAX_PARTY; i++ ) {
  572. if( p->data[i].sd != NULL ) {
  573. clif_party_withdraw(p->data[i].sd,p->party.member[i].account_id,p->party.member[i].name,PARTY_MEMBER_WITHDRAW_EXPEL,SELF);
  574. p->data[i].sd->status.party_id=0;
  575. }
  576. }
  577. idb_remove(party_db,party_id);
  578. return 1;
  579. }
  580. int party_changeoption(struct map_session_data *sd,int exp,int item)
  581. {
  582. nullpo_ret(sd);
  583. if( sd->status.party_id == 0 )
  584. return -3;
  585. intif_party_changeoption(sd->status.party_id,sd->status.account_id,exp,item);
  586. return 0;
  587. }
  588. //options: 0-exp, 1-item share, 2-pickup distribution
  589. int party_setoption(struct party_data *party, int option, int flag)
  590. {
  591. int i;
  592. ARR_FIND(0,MAX_PARTY,i,party->party.member[i].leader);
  593. if(i >= MAX_PARTY)
  594. return 0;
  595. switch(option) {
  596. case 0:
  597. intif_party_changeoption(party->party.party_id,party->party.member[i].account_id,flag,party->party.item);
  598. break;
  599. case 1:
  600. if(flag) flag = party->party.item|1;
  601. else flag = party->party.item&~1;
  602. intif_party_changeoption(party->party.party_id,party->party.member[i].account_id,party->party.exp,flag);
  603. break;
  604. case 2:
  605. if(flag) flag = party->party.item|2;
  606. else flag = party->party.item&~2;
  607. intif_party_changeoption(party->party.party_id,party->party.member[i].account_id,party->party.exp,flag);
  608. break;
  609. default:
  610. return 0;
  611. break;
  612. }
  613. return 1;
  614. }
  615. int party_optionchanged(int party_id,uint32 account_id,int exp,int item,int flag)
  616. {
  617. struct party_data *p;
  618. struct map_session_data *sd=map_id2sd(account_id);
  619. if( (p = party_search(party_id)) == NULL)
  620. return 0;
  621. //Flag&1: Exp change denied. Flag&2: Item change denied.
  622. if(!(flag&0x01) && p->party.exp != exp)
  623. p->party.exp = exp;
  624. if(!(flag&0x10) && p->party.item != item) {
  625. p->party.item = item;
  626. }
  627. clif_party_option(p,sd,flag);
  628. return 0;
  629. }
  630. int party_changeleader(struct map_session_data *sd, struct map_session_data *tsd, struct party_data *p)
  631. {
  632. int mi, tmi;
  633. if ( !p ) {
  634. if (!sd || !sd->status.party_id)
  635. return -1;
  636. if (!tsd || tsd->status.party_id != sd->status.party_id) {
  637. clif_displaymessage(sd->fd, msg_txt(sd,283));
  638. return -3;
  639. }
  640. if ( map_getmapflag(sd->bl.m, MF_PARTYLOCK) ) {
  641. clif_displaymessage(sd->fd, msg_txt(sd,287));
  642. return 0;
  643. }
  644. if ((p = party_search(sd->status.party_id)) == NULL )
  645. return -1;
  646. ARR_FIND( 0, MAX_PARTY, mi, p->data[mi].sd == sd );
  647. if (mi == MAX_PARTY)
  648. return 0; // Shouldn't happen
  649. if (!p->party.member[mi].leader) { // Need to be a party leader.
  650. clif_displaymessage(sd->fd, msg_txt(sd,282));
  651. return 0;
  652. }
  653. ARR_FIND( 0, MAX_PARTY, tmi, p->data[tmi].sd == tsd);
  654. if (tmi == MAX_PARTY)
  655. return 0; // Shouldn't happen
  656. if (battle_config.change_party_leader_samemap && p->party.member[mi].map != p->party.member[tmi].map) {
  657. clif_msg(sd, PARTY_MASTER_CHANGE_SAME_MAP);
  658. return 0;
  659. }
  660. } else {
  661. ARR_FIND(0,MAX_PARTY,mi,p->party.member[mi].leader);
  662. if (mi == MAX_PARTY)
  663. return 0; // Shouldn't happen
  664. ARR_FIND(0,MAX_PARTY,tmi,p->data[tmi].sd == tsd);
  665. if (tmi == MAX_PARTY)
  666. return 0; // Shouldn't happen
  667. }
  668. // Change leadership.
  669. p->party.member[mi].leader = 0;
  670. p->party.member[tmi].leader = 1;
  671. // Update members
  672. clif_party_leaderchanged(p->data[mi].sd, p->data[mi].sd->status.account_id, p->data[tmi].sd->status.account_id);
  673. // Update info.
  674. intif_party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id);
  675. clif_party_info(p,NULL);
  676. return 1;
  677. }
  678. /// Invoked (from char-server) when a party member
  679. /// - changes maps
  680. /// - logs in or out
  681. /// - gains a level (disabled)
  682. int party_recv_movemap(int party_id,uint32 account_id,uint32 char_id, unsigned short map_idx,int online,int lv)
  683. {
  684. struct party_member* m;
  685. struct party_data* p;
  686. int i;
  687. p = party_search(party_id);
  688. if( p == NULL )
  689. return 0;
  690. ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
  691. if( i == MAX_PARTY ) {
  692. ShowError("party_recv_movemap: char %d/%d not found in party %s (id:%d)",account_id,char_id,p->party.name,party_id);
  693. return 0;
  694. }
  695. m = &p->party.member[i];
  696. m->map = map_idx;
  697. m->online = online;
  698. m->lv = lv;
  699. //Check if they still exist on this map server
  700. p->data[i].sd = party_sd_check(party_id, account_id, char_id);
  701. clif_party_info(p,NULL);
  702. return 0;
  703. }
  704. void party_send_movemap(struct map_session_data *sd)
  705. {
  706. struct party_data *p;
  707. if( !sd->status.party_id )
  708. return;
  709. intif_party_changemap(sd,1);
  710. p=party_search(sd->status.party_id);
  711. if (!p) return;
  712. if(sd->state.connect_new) {
  713. //Note that this works because this function is invoked before connect_new is cleared.
  714. clif_party_option(p,sd,0x100);
  715. clif_party_info(p,sd);
  716. clif_party_member_info(p,sd);
  717. }
  718. if (sd->fd) { // synchronize minimap positions with the rest of the party
  719. int i;
  720. for(i=0; i < MAX_PARTY; i++) {
  721. if (p->data[i].sd &&
  722. p->data[i].sd != sd &&
  723. p->data[i].sd->bl.m == sd->bl.m)
  724. {
  725. clif_party_xy_single(sd->fd, p->data[i].sd);
  726. clif_party_xy_single(p->data[i].sd->fd, sd);
  727. }
  728. }
  729. }
  730. return;
  731. }
  732. void party_send_levelup(struct map_session_data *sd)
  733. {
  734. intif_party_changemap(sd,1);
  735. }
  736. int party_send_logout(struct map_session_data *sd)
  737. {
  738. struct party_data *p;
  739. int i;
  740. if(!sd->status.party_id)
  741. return 0;
  742. intif_party_changemap(sd,0);
  743. p=party_search(sd->status.party_id);
  744. if(!p) return 0;
  745. ARR_FIND( 0, MAX_PARTY, i, p->data[i].sd == sd );
  746. if( i < MAX_PARTY )
  747. memset(&p->data[i], 0, sizeof(p->data[0]));
  748. else
  749. ShowError("party_send_logout: Failed to locate member %d:%d in party %d!\n", sd->status.account_id, sd->status.char_id, p->party.party_id);
  750. return 1;
  751. }
  752. int party_send_message(struct map_session_data *sd,const char *mes,int len)
  753. {
  754. if(sd->status.party_id == 0)
  755. return 0;
  756. intif_party_message(sd->status.party_id,sd->status.account_id,mes,len);
  757. party_recv_message(sd->status.party_id,sd->status.account_id,mes,len);
  758. // Chat logging type 'P' / Party Chat
  759. log_chat(LOG_CHAT_PARTY, sd->status.party_id, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes);
  760. return 0;
  761. }
  762. int party_recv_message(int party_id,uint32 account_id,const char *mes,int len)
  763. {
  764. struct party_data *p;
  765. if( (p=party_search(party_id))==NULL)
  766. return 0;
  767. clif_party_message(p,account_id,mes,len);
  768. return 0;
  769. }
  770. int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv)
  771. {
  772. struct party_data *p;
  773. struct map_session_data *p_sd;
  774. int i;
  775. if(!party_id || (p = party_search(party_id)) == NULL)
  776. return 0;
  777. party_check_state(p);
  778. switch(skill_id) {
  779. case TK_COUNTER: //Increase Triple Attack rate of Monks.
  780. if (!p->state.monk) return 0;
  781. break;
  782. case MO_COMBOFINISH: //Increase Counter rate of Star Gladiators
  783. if (!p->state.sg) return 0;
  784. break;
  785. case AM_TWILIGHT2: //Twilight Pharmacy, requires Super Novice
  786. return p->state.snovice;
  787. case AM_TWILIGHT3: //Twilight Pharmacy, Requires Taekwon
  788. return p->state.tk;
  789. default:
  790. return 0; //Unknown case?
  791. }
  792. for(i = 0; i < MAX_PARTY; i++) {
  793. if ((p_sd = p->data[i].sd) == NULL)
  794. continue;
  795. if (sd->bl.m != p_sd->bl.m)
  796. continue;
  797. switch(skill_id) {
  798. case TK_COUNTER: //Increase Triple Attack rate of Monks.
  799. if((p_sd->class_&MAPID_UPPERMASK) == MAPID_MONK
  800. && pc_checkskill(p_sd,MO_TRIPLEATTACK)) {
  801. sc_start4(&p_sd->bl,&p_sd->bl,SC_SKILLRATE_UP,100,MO_TRIPLEATTACK,
  802. 50+50*skill_lv, //+100/150/200% rate
  803. 0,0,skill_get_time(SG_FRIEND, 1));
  804. }
  805. break;
  806. case MO_COMBOFINISH: //Increase Counter rate of Star Gladiators
  807. if((p_sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR
  808. && sd->sc.data[SC_READYCOUNTER]
  809. && pc_checkskill(p_sd,SG_FRIEND)) {
  810. sc_start4(&p_sd->bl,&p_sd->bl,SC_SKILLRATE_UP,100,TK_COUNTER,
  811. 50+50*pc_checkskill(p_sd,SG_FRIEND), //+100/150/200% rate
  812. 0,0,skill_get_time(SG_FRIEND, 1));
  813. }
  814. break;
  815. }
  816. }
  817. return 0;
  818. }
  819. TIMER_FUNC(party_send_xy_timer){
  820. struct party_data* p;
  821. DBIterator *iter = db_iterator(party_db);
  822. // for each existing party
  823. for( p = (struct party_data*)dbi_first(iter); dbi_exists(iter); p = (struct party_data*)dbi_next(iter) ) {
  824. int i;
  825. if( !p->party.count ) // no online party members so do not iterate
  826. continue;
  827. // for each member of this party
  828. for( i = 0; i < MAX_PARTY; i++ ) {
  829. struct map_session_data* sd = p->data[i].sd;
  830. if( !sd )
  831. continue;
  832. if( p->data[i].x != sd->bl.x || p->data[i].y != sd->bl.y ) { // perform position update
  833. clif_party_xy(sd);
  834. p->data[i].x = sd->bl.x;
  835. p->data[i].y = sd->bl.y;
  836. }
  837. if (battle_config.party_hp_mode && p->data[i].hp != sd->battle_status.hp) { // perform hp update
  838. clif_party_hp(sd);
  839. p->data[i].hp = sd->battle_status.hp;
  840. }
  841. }
  842. }
  843. dbi_destroy(iter);
  844. return 0;
  845. }
  846. int party_send_xy_clear(struct party_data *p)
  847. {
  848. int i;
  849. nullpo_ret(p);
  850. for(i = 0; i < MAX_PARTY; i++) {
  851. if(!p->data[i].sd)
  852. continue;
  853. p->data[i].hp = 0;
  854. p->data[i].x = 0;
  855. p->data[i].y = 0;
  856. }
  857. return 0;
  858. }
  859. /** Party EXP and Zeny sharing
  860. * @param p Party data
  861. * @param src EXP source (for renewal level penalty)
  862. * @param base_exp Base EXP gained from killed mob
  863. * @param job_exp Job EXP gained from killed mob
  864. * @param zeny Zeny gained from killed mob
  865. * @author Valaris
  866. **/
  867. void party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny)
  868. {
  869. struct map_session_data* sd[MAX_PARTY];
  870. unsigned int i, c;
  871. #ifdef RENEWAL_EXP
  872. TBL_MOB *md = BL_CAST(BL_MOB, src);
  873. if (!md)
  874. return;
  875. #endif
  876. nullpo_retv(p);
  877. // count the number of players eligible for exp sharing
  878. for (i = c = 0; i < MAX_PARTY; i++) {
  879. if( (sd[c] = p->data[i].sd) == NULL || sd[c]->bl.m != src->m || pc_isdead(sd[c]) || (battle_config.idle_no_share && pc_isidle(sd[c])) )
  880. continue;
  881. c++;
  882. }
  883. if (c < 1)
  884. return;
  885. base_exp/=c;
  886. job_exp/=c;
  887. zeny/=c;
  888. if (battle_config.party_even_share_bonus && c > 1) {
  889. double bonus = 100 + battle_config.party_even_share_bonus*(c-1);
  890. if (base_exp)
  891. base_exp = (unsigned int) cap_value(base_exp * bonus/100, 0, UINT_MAX);
  892. if (job_exp)
  893. job_exp = (unsigned int) cap_value(job_exp * bonus/100, 0, UINT_MAX);
  894. if (zeny)
  895. zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX);
  896. }
  897. for (i = 0; i < c; i++) {
  898. #ifdef RENEWAL_EXP
  899. uint32 base_gained = base_exp, job_gained = job_exp;
  900. if (base_exp || job_exp) {
  901. int rate = pc_level_penalty_mod(md->level - sd[i]->status.base_level, md->db->status.class_, md->db->status.mode, 1);
  902. if (rate != 100) {
  903. if (base_exp)
  904. base_gained = (unsigned int)cap_value(apply_rate(base_exp, rate), 1, UINT_MAX);
  905. if (job_exp)
  906. job_gained = (unsigned int)cap_value(apply_rate(job_exp, rate), 1, UINT_MAX);
  907. }
  908. }
  909. pc_gainexp(sd[i], src, base_gained, job_gained, 0);
  910. #else
  911. pc_gainexp(sd[i], src, base_exp, job_exp, 0);
  912. #endif
  913. if (zeny) // zeny from mobs [Valaris]
  914. pc_getzeny(sd[i],zeny,LOG_TYPE_PICKDROP_MONSTER,NULL);
  915. }
  916. }
  917. //Does party loot. first_charid holds the charid of the player who has time priority to take the item.
  918. int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid)
  919. {
  920. TBL_PC* target = NULL;
  921. int i;
  922. if (p && p->party.item&2 && (first_charid || !(battle_config.party_share_type&1))) {
  923. //item distribution to party members.
  924. if (battle_config.party_share_type&2) { // Round Robin
  925. TBL_PC* psd;
  926. i = p->itemc;
  927. do {
  928. i++;
  929. if (i >= MAX_PARTY)
  930. i = 0; // reset counter to 1st person in party so it'll stop when it reaches "itemc"
  931. if( (psd = p->data[i].sd) == NULL || sd->bl.m != psd->bl.m || pc_isdead(psd) || (battle_config.idle_no_share && pc_isidle(psd)) )
  932. continue;
  933. if (pc_additem(psd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER))
  934. continue; //Chosen char can't pick up loot.
  935. //Successful pick.
  936. p->itemc = i;
  937. target = psd;
  938. break;
  939. } while (i != p->itemc);
  940. } else { // Random pick
  941. TBL_PC* psd[MAX_PARTY];
  942. int count = 0;
  943. //Collect pick candidates
  944. for (i = 0; i < MAX_PARTY; i++) {
  945. if( (psd[count] = p->data[i].sd) == NULL || psd[count]->bl.m != sd->bl.m || pc_isdead(psd[count]) || (battle_config.idle_no_share && pc_isidle(psd[count])) )
  946. continue;
  947. count++;
  948. }
  949. while (count > 0) { //Pick a random member.
  950. i = rnd()%count;
  951. if (pc_additem(psd[i],item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
  952. psd[i] = psd[count-1];
  953. count--;
  954. } else { // Successful pick.
  955. target = psd[i];
  956. break;
  957. }
  958. }
  959. }
  960. }
  961. if (!target) {
  962. target = sd; //Give it to the char that picked it up
  963. if ((i = pc_additem(sd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER)))
  964. return i;
  965. }
  966. if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item->nameid)) )
  967. clif_party_show_picker(target, item);
  968. return 0;
  969. }
  970. int party_send_dot_remove(struct map_session_data *sd)
  971. {
  972. if (sd->status.party_id)
  973. clif_party_xy_remove(sd);
  974. return 0;
  975. }
  976. /**
  977. * Check whether a party member is in autotrade or idle for count functions
  978. * @param bl: Object invoking the counter
  979. * @param ap: List of parameters
  980. * @return 1 when neither autotrading and not idle or 0 otherwise
  981. */
  982. int party_sub_count(struct block_list *bl, va_list ap)
  983. {
  984. struct map_session_data *sd = (TBL_PC *)bl;
  985. if (sd->state.autotrade)
  986. return 0;
  987. if (battle_config.idle_no_share && pc_isidle(sd))
  988. return 0;
  989. return 1;
  990. }
  991. /**
  992. * To use for counting classes in a party.
  993. * @param bl: Object invoking the counter
  994. * @param ap: List of parameters: Class_Mask, Class_ID
  995. * @return 1 when class exists in party or 0 otherwise
  996. */
  997. int party_sub_count_class(struct block_list *bl, va_list ap)
  998. {
  999. struct map_session_data *sd = (TBL_PC *)bl;
  1000. unsigned int mask = va_arg(ap, unsigned int);
  1001. unsigned int mapid_class = va_arg(ap, unsigned int);
  1002. if( !party_sub_count(bl, ap) )
  1003. return 0;
  1004. if( (sd->class_&mask) != mapid_class )
  1005. return 0;
  1006. return 1;
  1007. }
  1008. /// Executes 'func' for each party member on the same map and in range (0:whole map)
  1009. int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_session_data *sd,int range,...)
  1010. {
  1011. struct party_data *p;
  1012. int i;
  1013. int x0,y0,x1,y1;
  1014. struct block_list *list[MAX_PARTY];
  1015. int blockcount=0;
  1016. int total = 0; //Return value.
  1017. nullpo_ret(sd);
  1018. if((p = party_search(sd->status.party_id)) == NULL)
  1019. return 0;
  1020. x0 = sd->bl.x-range;
  1021. y0 = sd->bl.y-range;
  1022. x1 = sd->bl.x+range;
  1023. y1 = sd->bl.y+range;
  1024. for(i = 0; i < MAX_PARTY; i++) {
  1025. struct map_session_data *psd = p->data[i].sd;
  1026. if(!psd)
  1027. continue;
  1028. if(psd->bl.m!=sd->bl.m || !psd->bl.prev)
  1029. continue;
  1030. if(range &&
  1031. (psd->bl.x<x0 || psd->bl.y<y0 ||
  1032. psd->bl.x>x1 || psd->bl.y>y1 ) )
  1033. continue;
  1034. list[blockcount++]=&psd->bl;
  1035. }
  1036. map_freeblock_lock();
  1037. for(i = 0; i < blockcount; i++) {
  1038. va_list ap;
  1039. va_start(ap, range);
  1040. total += func(list[i], ap);
  1041. va_end(ap);
  1042. }
  1043. map_freeblock_unlock();
  1044. return total;
  1045. }
  1046. /*==========================================
  1047. * Party Booking in KRO [Spiria]
  1048. *------------------------------------------*/
  1049. static struct party_booking_ad_info* create_party_booking_data(void)
  1050. {
  1051. struct party_booking_ad_info *pb_ad;
  1052. CREATE(pb_ad, struct party_booking_ad_info, 1);
  1053. pb_ad->index = party_booking_nextid++;
  1054. return pb_ad;
  1055. }
  1056. void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job)
  1057. {
  1058. struct party_booking_ad_info *pb_ad;
  1059. int i;
  1060. pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
  1061. if( pb_ad == NULL ) {
  1062. pb_ad = create_party_booking_data();
  1063. idb_put(party_booking_db, sd->status.char_id, pb_ad);
  1064. } else { // already registered
  1065. clif_PartyBookingRegisterAck(sd, 2);
  1066. return;
  1067. }
  1068. memcpy(pb_ad->charname,sd->status.name,NAME_LENGTH);
  1069. pb_ad->starttime = (int)time(NULL);
  1070. pb_ad->p_detail.level = level;
  1071. pb_ad->p_detail.mapid = mapid;
  1072. for(i = 0; i < MAX_PARTY_BOOKING_JOBS; i++)
  1073. if(job[i] != 0xFF)
  1074. pb_ad->p_detail.job[i] = job[i];
  1075. else pb_ad->p_detail.job[i] = -1;
  1076. clif_PartyBookingRegisterAck(sd, 0);
  1077. clif_PartyBookingInsertNotify(sd, pb_ad); // Notice
  1078. }
  1079. void party_booking_update(struct map_session_data *sd, short* job)
  1080. {
  1081. int i;
  1082. struct party_booking_ad_info *pb_ad;
  1083. pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
  1084. if( pb_ad == NULL )
  1085. return;
  1086. pb_ad->starttime = (int)time(NULL);// Update time.
  1087. for(i = 0; i < MAX_PARTY_BOOKING_JOBS; i++)
  1088. if(job[i] != 0xFF)
  1089. pb_ad->p_detail.job[i] = job[i];
  1090. else
  1091. pb_ad->p_detail.job[i] = -1;
  1092. clif_PartyBookingUpdateNotify(sd, pb_ad);
  1093. }
  1094. void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount)
  1095. {
  1096. struct party_booking_ad_info *pb_ad;
  1097. int i, count=0;
  1098. struct party_booking_ad_info* result_list[MAX_PARTY_BOOKING_RESULTS];
  1099. bool more_result = false;
  1100. DBIterator* iter = db_iterator(party_booking_db);
  1101. memset(result_list, 0, sizeof(result_list));
  1102. for( pb_ad = (struct party_booking_ad_info*)dbi_first(iter); dbi_exists(iter); pb_ad = (struct party_booking_ad_info*)dbi_next(iter) ) {
  1103. if (pb_ad->index < lastindex || (level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level)))
  1104. continue;
  1105. if (count >= MAX_PARTY_BOOKING_RESULTS) {
  1106. more_result = true;
  1107. break;
  1108. }
  1109. if (mapid == 0 && job == -1)
  1110. result_list[count] = pb_ad;
  1111. else if (mapid == 0) {
  1112. for(i=0; i<MAX_PARTY_BOOKING_JOBS; i++)
  1113. if (pb_ad->p_detail.job[i] == job && job != -1)
  1114. result_list[count] = pb_ad;
  1115. } else if (job == -1) {
  1116. if (pb_ad->p_detail.mapid == mapid)
  1117. result_list[count] = pb_ad;
  1118. }
  1119. if( result_list[count] )
  1120. count++;
  1121. }
  1122. dbi_destroy(iter);
  1123. clif_PartyBookingSearchAck(sd->fd, result_list, count, more_result);
  1124. }
  1125. bool party_booking_delete(struct map_session_data *sd)
  1126. {
  1127. struct party_booking_ad_info* pb_ad;
  1128. if((pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id)) != NULL) {
  1129. clif_PartyBookingDeleteNotify(sd, pb_ad->index);
  1130. idb_remove(party_booking_db,sd->status.char_id);
  1131. }
  1132. return true;
  1133. }