· 9 years ago · Nov 05, 2016, 02:18 PM
1/**
2 * This file is part of Hercules.
3 * http://herc.ws - http://github.com/HerculesWS/Hercules
4 *
5 * Copyright (C) 2012-2016 Hercules Dev Team
6 * Copyright (C) Athena Dev Teams
7 *
8 * Hercules is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21#define HERCULES_CORE
22
23#include "config/core.h" // DBPATH, GP_BOUND_ITEMS, MAX_SPIRITBALL, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EXP, SECURE_NPCTIMEOUT
24#include "pc.h"
25
26#include "map/atcommand.h" // get_atcommand_level()
27#include "map/battle.h" // battle_config
28#include "map/battleground.h"
29#include "map/channel.h"
30#include "map/chat.h"
31#include "map/chrif.h"
32#include "map/clif.h"
33#include "map/date.h" // is_day_of_*()
34#include "map/duel.h"
35#include "map/elemental.h"
36#include "map/guild.h" // guild-"search(), guild_request_info()
37#include "map/homunculus.h"
38#include "map/instance.h"
39#include "map/intif.h"
40#include "map/itemdb.h"
41#include "map/log.h"
42#include "map/mail.h"
43#include "map/map.h"
44#include "map/mercenary.h"
45#include "map/mob.h" // struct mob_data
46#include "map/npc.h" // fake_nd
47#include "map/party.h" // party-"search()
48#include "map/path.h"
49#include "map/pc_groups.h"
50#include "map/pet.h" // pet_unlocktarget()
51#include "map/quest.h"
52#include "map/script.h" // script_config
53#include "map/skill.h"
54#include "map/status.h" // struct status_data
55#include "map/storage.h"
56#include "common/cbasetypes.h"
57#include "common/conf.h"
58#include "common/core.h" // get_svn_revision()
59#include "common/HPM.h"
60#include "common/memmgr.h"
61#include "common/mmo.h" // NAME_LENGTH, MAX_CARTS, NEW_CARTS
62#include "common/nullpo.h"
63#include "common/random.h"
64#include "common/showmsg.h"
65#include "common/socket.h"
66#include "common/sql.h"
67#include "common/strlib.h" // safestrncpy()
68#include "common/sysinfo.h"
69#include "common/timer.h"
70#include "common/utils.h"
71
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75#include <time.h>
76
77struct pc_interface pc_s;
78struct pc_interface *pc;
79
80//Converts a class to its array index for CLASS_COUNT defined arrays.
81//Note that it does not do a validity check for speed purposes, where parsing
82//player input make sure to use a pc->db_checkid first!
83int pc_class2idx(int class_) {
84 if (class_ >= JOB_NOVICE_HIGH) {
85 class_ += - JOB_NOVICE_HIGH + JOB_MAX_BASIC;
86 }
87 Assert_ret(class_ >= 0 && class_ < CLASS_COUNT);
88 return class_;
89}
90
91/**
92 * Creates a new dummy map session data.
93 * Used when there is no real player attached, but it is
94 * required to provide a session.
95 * Caller must release dummy on its own when it's no longer needed.
96 */
97struct map_session_data* pc_get_dummy_sd(void)
98{
99 struct map_session_data *dummy_sd;
100 CREATE(dummy_sd, struct map_session_data, 1);
101 dummy_sd->group = pcg->get_dummy_group(); // map_session_data.group is expected to be non-NULL at all times
102 return dummy_sd;
103}
104
105/**
106 * Sets player's group.
107 * Caller should handle error (preferably display message and disconnect).
108 * @param group_id Group ID
109 * @return 1 on error, 0 on success
110 */
111int pc_set_group(struct map_session_data *sd, int group_id)
112{
113 GroupSettings *group = pcg->id2group(group_id);
114 nullpo_retr(1, sd);
115 if (group == NULL)
116 return 1;
117 sd->group_id = group_id;
118 sd->group = group;
119 return 0;
120}
121
122/**
123 * Checks if commands used by player should be logged.
124 */
125bool pc_should_log_commands(struct map_session_data *sd)
126{
127 nullpo_retr(true, sd);
128 return pcg->should_log_commands(sd->group);
129}
130
131int pc_invincible_timer(int tid, int64 tick, int id, intptr_t data)
132{
133 struct map_session_data *sd = map->id2sd(id);
134
135 if (sd == NULL)
136 return 1;
137
138 if(sd->invincible_timer != tid){
139 ShowError("invincible_timer %d != %d\n",sd->invincible_timer,tid);
140 return 0;
141 }
142 sd->invincible_timer = INVALID_TIMER;
143 skill->unit_move(&sd->bl,tick,1);
144
145 return 0;
146}
147
148void pc_setinvincibletimer(struct map_session_data* sd, int val)
149{
150 nullpo_retv(sd);
151
152 val += map->list[sd->bl.m].invincible_time_inc;
153
154 if( sd->invincible_timer != INVALID_TIMER )
155 timer->delete(sd->invincible_timer,pc->invincible_timer);
156 sd->invincible_timer = timer->add(timer->gettick()+val,pc->invincible_timer,sd->bl.id,0);
157}
158
159void pc_delinvincibletimer(struct map_session_data* sd)
160{
161 nullpo_retv(sd);
162
163 if( sd->invincible_timer != INVALID_TIMER )
164 {
165 timer->delete(sd->invincible_timer,pc->invincible_timer);
166 sd->invincible_timer = INVALID_TIMER;
167 skill->unit_move(&sd->bl,timer->gettick(),1);
168 }
169}
170
171int pc_spiritball_timer(int tid, int64 tick, int id, intptr_t data) {
172 struct map_session_data *sd = map->id2sd(id);
173 int i;
174
175 if (sd == NULL)
176 return 1;
177
178 if( sd->spiritball <= 0 )
179 {
180 ShowError("pc_spiritball_timer: %d spiritball's available. (aid=%d cid=%d tid=%d)\n", sd->spiritball, sd->status.account_id, sd->status.char_id, tid);
181 sd->spiritball = 0;
182 return 0;
183 }
184
185 ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == tid);
186 if( i == sd->spiritball )
187 {
188 ShowError("pc_spiritball_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid);
189 return 0;
190 }
191
192 sd->spiritball--;
193 if( i != sd->spiritball )
194 memmove(sd->spirit_timer+i, sd->spirit_timer+i+1, (sd->spiritball-i)*sizeof(int));
195 sd->spirit_timer[sd->spiritball] = INVALID_TIMER;
196
197 clif->spiritball(&sd->bl);
198
199 return 0;
200}
201
202/**
203* Get the possible number of spiritball that a player can call.
204* @param sd the affected player structure
205* @param min the minimum number of spiritball regardless the level of MO_CALLSPIRITS
206* @retval total number of spiritball
207**/
208int pc_getmaxspiritball(struct map_session_data *sd, int min) {
209 int result;
210
211 nullpo_ret(sd);
212
213 result = pc->checkskill(sd, MO_CALLSPIRITS);
214
215 if ( min && result < min )
216 result = min;
217 else if ( sd->sc.data[SC_RAISINGDRAGON] )
218 result += sd->sc.data[SC_RAISINGDRAGON]->val1;
219 if ( result > MAX_SPIRITBALL )
220 result = MAX_SPIRITBALL;
221 return result;
222}
223
224int pc_addspiritball(struct map_session_data *sd,int interval,int max)
225{
226 int tid, i;
227
228 nullpo_ret(sd);
229
230 if(max > MAX_SPIRITBALL)
231 max = MAX_SPIRITBALL;
232 if(sd->spiritball < 0)
233 sd->spiritball = 0;
234
235 if( sd->spiritball && sd->spiritball >= max ) {
236 if(sd->spirit_timer[0] != INVALID_TIMER)
237 timer->delete(sd->spirit_timer[0],pc->spiritball_timer);
238 sd->spiritball--;
239 if( sd->spiritball != 0 )
240 memmove(sd->spirit_timer+0, sd->spirit_timer+1, (sd->spiritball)*sizeof(int));
241 sd->spirit_timer[sd->spiritball] = INVALID_TIMER;
242 }
243
244 tid = timer->add(timer->gettick()+interval, pc->spiritball_timer, sd->bl.id, 0);
245 ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->spirit_timer[i])->tick) < 0);
246 if( i != sd->spiritball )
247 memmove(sd->spirit_timer+i+1, sd->spirit_timer+i, (sd->spiritball-i)*sizeof(int));
248 sd->spirit_timer[i] = tid;
249 sd->spiritball++;
250 if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD )
251 clif->millenniumshield(&sd->bl,sd->spiritball);
252 else
253 clif->spiritball(&sd->bl);
254
255 return 0;
256}
257
258int pc_delspiritball(struct map_session_data *sd,int count,int type)
259{
260 int i;
261
262 nullpo_ret(sd);
263
264 if(sd->spiritball <= 0) {
265 sd->spiritball = 0;
266 return 0;
267 }
268
269 if(count <= 0)
270 return 0;
271 if(count > sd->spiritball)
272 count = sd->spiritball;
273 sd->spiritball -= count;
274 if(count > MAX_SPIRITBALL)
275 count = MAX_SPIRITBALL;
276
277 for(i=0;i<count;i++) {
278 if(sd->spirit_timer[i] != INVALID_TIMER) {
279 timer->delete(sd->spirit_timer[i],pc->spiritball_timer);
280 sd->spirit_timer[i] = INVALID_TIMER;
281 }
282 }
283 for(i=count;i<MAX_SPIRITBALL;i++) {
284 sd->spirit_timer[i-count] = sd->spirit_timer[i];
285 sd->spirit_timer[i] = INVALID_TIMER;
286 }
287
288 if(!type) {
289 if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD )
290 clif->millenniumshield(&sd->bl,sd->spiritball);
291 else
292 clif->spiritball(&sd->bl);
293 }
294 return 0;
295}
296int pc_check_banding(struct block_list *bl, va_list ap)
297{
298 int *c, *b_sd;
299 struct block_list *src;
300 const struct map_session_data *tsd;
301 struct status_change *sc;
302
303 nullpo_ret(bl);
304 Assert_ret(bl->type == BL_PC);
305 tsd = BL_UCCAST(BL_PC, bl);
306
307 nullpo_ret(src = va_arg(ap,struct block_list *));
308 c = va_arg(ap,int *);
309 b_sd = va_arg(ap, int *);
310
311 if(pc_isdead(tsd))
312 return 0;
313
314 sc = status->get_sc(bl);
315
316 if( sc && sc->data[SC_BANDING] )
317 {
318 b_sd[(*c)++] = tsd->bl.id;
319 return 1;
320 }
321
322 return 0;
323}
324int pc_banding(struct map_session_data *sd, uint16 skill_lv) {
325 int c;
326 int b_sd[MAX_PARTY]; // In case of a full Royal Guard party.
327 int i, j, hp, extra_hp = 0, tmp_qty = 0;
328 struct map_session_data *bsd;
329 struct status_change *sc;
330 int range = skill->get_splash(LG_BANDING,skill_lv);
331
332 nullpo_ret(sd);
333
334 c = 0;
335 memset(b_sd, 0, sizeof(b_sd));
336 i = party->foreachsamemap(pc->check_banding,sd,range,&sd->bl,&c,&b_sd);
337
338 if( c < 1 ) {
339 //just recalc status no need to recalc hp
340 if( (sc = status->get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) {
341 // No more Royal Guards in Banding found.
342 sc->data[SC_BANDING]->val2 = 0; // Reset the counter
343 status_calc_bl(&sd->bl, status->sc2scb_flag(SC_BANDING));
344 }
345 return 0;
346 }
347
348 //Add yourself
349 hp = status_get_hp(&sd->bl);
350 i++;
351
352 // Get total HP of all Royal Guards in party.
353 for( j = 0; j < i; j++ ) {
354 bsd = map->id2sd(b_sd[j]);
355 if( bsd != NULL )
356 hp += status_get_hp(&bsd->bl);
357 }
358
359 // Set average HP.
360 hp = hp / i;
361
362 // If a Royal Guard have full HP, give more HP to others that haven't full HP.
363 for (j = 0; j < i; j++) {
364 int tmp_hp;
365 bsd = map->id2sd(b_sd[j]);
366 if (bsd != NULL && (tmp_hp = hp - status_get_max_hp(&bsd->bl)) > 0) {
367 extra_hp += tmp_hp;
368 tmp_qty++;
369 }
370 }
371
372 if( extra_hp > 0 && tmp_qty > 0 )
373 hp += extra_hp / tmp_qty;
374
375 for( j = 0; j < i; j++ ) {
376 bsd = map->id2sd(b_sd[j]);
377 if( bsd != NULL ) {
378 status->set_hp(&bsd->bl,hp,0); // Set hp
379 if( (sc = status->get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) {
380 sc->data[SC_BANDING]->val2 = c; // Set the counter. It doesn't count your self.
381 status_calc_bl(&bsd->bl, status->sc2scb_flag(SC_BANDING)); // Set atk and def.
382 }
383 }
384 }
385
386 return c;
387}
388
389// Increases a player's fame points and displays a notice to him
390void pc_addfame(struct map_session_data *sd,int count)
391{
392 int ranktype = -1;
393 nullpo_retv(sd);
394 sd->status.fame += count;
395 if(sd->status.fame > MAX_FAME)
396 sd->status.fame = MAX_FAME;
397 switch(sd->class_&MAPID_UPPERMASK){
398 case MAPID_BLACKSMITH: ranktype = RANKTYPE_BLACKSMITH; break;
399 case MAPID_ALCHEMIST: ranktype = RANKTYPE_ALCHEMIST; break;
400 case MAPID_TAEKWON: ranktype = RANKTYPE_TAEKWON; break;
401 }
402 clif->update_rankingpoint(sd, ranktype, count);
403 chrif->updatefamelist(sd);
404}
405
406// Check whether a player ID is in the fame rankers' list of its job, returns his/her position if so, 0 else
407unsigned char pc_famerank(int char_id, int job)
408{
409 int i;
410
411 switch(job){
412 case MAPID_BLACKSMITH: // Blacksmith
413 for(i = 0; i < MAX_FAME_LIST; i++){
414 if(pc->smith_fame_list[i].id == char_id)
415 return i + 1;
416 }
417 break;
418 case MAPID_ALCHEMIST: // Alchemist
419 for(i = 0; i < MAX_FAME_LIST; i++){
420 if(pc->chemist_fame_list[i].id == char_id)
421 return i + 1;
422 }
423 break;
424 case MAPID_TAEKWON: // Taekwon
425 for(i = 0; i < MAX_FAME_LIST; i++){
426 if(pc->taekwon_fame_list[i].id == char_id)
427 return i + 1;
428 }
429 break;
430 }
431
432 return 0;
433}
434
435int pc_setrestartvalue(struct map_session_data *sd,int type) {
436 struct status_data *st, *bst;
437 nullpo_ret(sd);
438
439 bst = &sd->base_status;
440 st = &sd->battle_status;
441
442 if (type&1) {
443 //Normal resurrection
444 st->hp = 1; //Otherwise status->heal may fail if dead.
445 status->heal(&sd->bl, bst->hp, 0, 1);
446 if( st->sp < bst->sp )
447 status->set_sp(&sd->bl, bst->sp, 1);
448 } else { //Just for saving on the char-server (with values as if respawned)
449 sd->status.hp = bst->hp;
450 sd->status.sp = (st->sp < bst->sp) ? bst->sp : st->sp;
451 }
452 return 0;
453}
454
455/*==========================================
456 Rental System
457 *------------------------------------------*/
458int pc_inventory_rental_end(int tid, int64 tick, int id, intptr_t data) {
459 struct map_session_data *sd = map->id2sd(id);
460 if( sd == NULL )
461 return 0;
462 if( tid != sd->rental_timer )
463 {
464 ShowError("pc_inventory_rental_end: invalid timer id.\n");
465 return 0;
466 }
467
468 pc->inventory_rentals(sd);
469 return 1;
470}
471
472int pc_inventory_rental_clear(struct map_session_data *sd)
473{
474 nullpo_ret(sd);
475 if( sd->rental_timer != INVALID_TIMER )
476 {
477 timer->delete(sd->rental_timer, pc->inventory_rental_end);
478 sd->rental_timer = INVALID_TIMER;
479 }
480
481 return 1;
482}
483/* assumes i is valid (from default areas where it is called, it is) */
484void pc_rental_expire(struct map_session_data *sd, int i) {
485 short nameid;
486
487 nullpo_retv(sd);
488 Assert_retv(i >= 0 && i < MAX_INVENTORY);
489 nameid = sd->status.inventory[i].nameid;
490
491 /* Soon to be dropped, we got plans to integrate it with item db */
492 switch( nameid ) {
493 case ITEMID_REINS_OF_MOUNT:
494 status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER);
495 break;
496 case ITEMID_LOVE_ANGEL:
497 if( sd->status.font == 1 ) {
498 sd->status.font = 0;
499 clif->font(sd);
500 }
501 break;
502 case ITEMID_SQUIRREL:
503 if( sd->status.font == 2 ) {
504 sd->status.font = 0;
505 clif->font(sd);
506 }
507 break;
508 case ITEMID_GOGO:
509 if( sd->status.font == 3 ) {
510 sd->status.font = 0;
511 clif->font(sd);
512 }
513 break;
514 case ITEMID_PICTURE_DIARY:
515 if( sd->status.font == 4 ) {
516 sd->status.font = 0;
517 clif->font(sd);
518 }
519 break;
520 case ITEMID_MINI_HEART:
521 if( sd->status.font == 5 ) {
522 sd->status.font = 0;
523 clif->font(sd);
524 }
525 break;
526 case ITEMID_NEWCOMER:
527 if( sd->status.font == 6 ) {
528 sd->status.font = 0;
529 clif->font(sd);
530 }
531 break;
532 case ITEMID_KID:
533 if( sd->status.font == 7 ) {
534 sd->status.font = 0;
535 clif->font(sd);
536 }
537 break;
538 case ITEMID_MAGIC_CASTLE:
539 if( sd->status.font == 8 ) {
540 sd->status.font = 0;
541 clif->font(sd);
542 }
543 break;
544 case ITEMID_BULGING_HEAD:
545 if( sd->status.font == 9 ) {
546 sd->status.font = 0;
547 clif->font(sd);
548 }
549 break;
550 }
551
552 clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid);
553 pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_RENTAL);
554}
555void pc_inventory_rentals(struct map_session_data *sd)
556{
557 int i, c = 0;
558 int64 expire_tick, next_tick = INT64_MAX;
559
560 nullpo_retv(sd);
561 for( i = 0; i < MAX_INVENTORY; i++ )
562 { // Check for Rentals on Inventory
563 if( sd->status.inventory[i].nameid == 0 )
564 continue; // Nothing here
565 if( sd->status.inventory[i].expire_time == 0 )
566 continue;
567
568 if( sd->status.inventory[i].expire_time <= time(NULL) ) {
569 pc->rental_expire(sd,i);
570 } else {
571 expire_tick = (int64)(sd->status.inventory[i].expire_time - time(NULL)) * 1000;
572 clif->rental_time(sd->fd, sd->status.inventory[i].nameid, (int)(expire_tick / 1000));
573 next_tick = min(expire_tick, next_tick);
574 c++;
575 }
576 }
577
578 if( c > 0 ) // min(next_tick,3600000) 1 hour each timer to keep announcing to the owner, and to avoid a but with rental time > 15 days
579 sd->rental_timer = timer->add(timer->gettick() + min(next_tick,3600000), pc->inventory_rental_end, sd->bl.id, 0);
580 else
581 sd->rental_timer = INVALID_TIMER;
582}
583
584void pc_inventory_rental_add(struct map_session_data *sd, int seconds)
585{
586 int tick = seconds * 1000;
587
588 if( sd == NULL )
589 return;
590
591 if( sd->rental_timer != INVALID_TIMER )
592 {
593 const struct TimerData * td;
594 td = timer->get(sd->rental_timer);
595 if( DIFF_TICK(td->tick, timer->gettick()) > tick )
596 { // Update Timer as this one ends first than the current one
597 pc->inventory_rental_clear(sd);
598 sd->rental_timer = timer->add(timer->gettick() + tick, pc->inventory_rental_end, sd->bl.id, 0);
599 }
600 }
601 else
602 sd->rental_timer = timer->add(timer->gettick() + min(tick,3600000), pc->inventory_rental_end, sd->bl.id, 0);
603}
604
605/*==========================================
606 * prepares character for saving.
607 *------------------------------------------*/
608int pc_makesavestatus(struct map_session_data *sd)
609{
610 nullpo_ret(sd);
611
612 if(!battle_config.save_clothcolor)
613 sd->status.clothes_color=0;
614
615 if (!battle_config.save_body_style)
616 sd->status.body = 0;
617
618
619 //Only copy the Cart/Peco/Falcon options, the rest are handled via
620 //status change load/saving. [Skotlex]
621#ifdef NEW_CARTS
622 sd->status.option = sd->sc.option&(OPTION_INVISIBLE|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_WUGRIDER|OPTION_MADOGEAR);
623#else
624 sd->status.option = sd->sc.option&(OPTION_INVISIBLE|OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_WUGRIDER|OPTION_MADOGEAR);
625#endif
626 if (sd->sc.data[SC_JAILED]) { //When Jailed, do not move last point.
627 if(pc_isdead(sd)){
628 pc->setrestartvalue(sd,0);
629 } else {
630 sd->status.hp = sd->battle_status.hp;
631 sd->status.sp = sd->battle_status.sp;
632 }
633 sd->status.last_point.map = sd->mapindex;
634 sd->status.last_point.x = sd->bl.x;
635 sd->status.last_point.y = sd->bl.y;
636 return 0;
637 }
638
639 if(pc_isdead(sd)){
640 pc->setrestartvalue(sd,0);
641 memcpy(&sd->status.last_point,&sd->status.save_point,sizeof(sd->status.last_point));
642 } else {
643 sd->status.hp = sd->battle_status.hp;
644 sd->status.sp = sd->battle_status.sp;
645 sd->status.last_point.map = sd->mapindex;
646 sd->status.last_point.x = sd->bl.x;
647 sd->status.last_point.y = sd->bl.y;
648 }
649
650 if( ( map->list[sd->bl.m].flag.nosave && sd->state.autotrade != 2 ) || map->list[sd->bl.m].instance_id >= 0) {
651 struct map_data *m=&map->list[sd->bl.m];
652 if(m->save.map)
653 memcpy(&sd->status.last_point,&m->save,sizeof(sd->status.last_point));
654 else
655 memcpy(&sd->status.last_point,&sd->status.save_point,sizeof(sd->status.last_point));
656 }
657 if( sd->status.last_point.map == 0 ) {
658 sd->status.last_point.map = 1;
659 sd->status.last_point.x = 0;
660 sd->status.last_point.y = 0;
661 }
662
663 if( sd->status.save_point.map == 0 ) {
664 sd->status.save_point.map = 1;
665 sd->status.save_point.x = 0;
666 sd->status.save_point.y = 0;
667 }
668 return 0;
669}
670
671/*==========================================
672 * Off init ? Connection?
673 *------------------------------------------*/
674int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int login_id1, unsigned int client_tick, int sex, int fd)
675{
676 nullpo_ret(sd);
677
678 sd->bl.id = account_id;
679 sd->status.account_id = account_id;
680 sd->status.char_id = char_id;
681 sd->status.sex = sex;
682 sd->login_id1 = login_id1;
683 sd->login_id2 = 0; // at this point, we can not know the value :(
684 sd->client_tick = client_tick;
685 sd->state.active = 0; //to be set to 1 after player is fully authed and loaded.
686 sd->bl.type = BL_PC;
687 sd->canlog_tick = timer->gettick();
688 //Required to prevent homunculus copuing a base speed of 0.
689 sd->battle_status.speed = sd->base_status.speed = DEFAULT_WALK_SPEED;
690 sd->state.warp_clean = 1;
691 sd->catch_target_class = -1;
692 return 0;
693}
694
695int pc_equippoint(struct map_session_data *sd,int n)
696{
697 int ep = 0;
698
699 nullpo_ret(sd);
700 Assert_ret(n >= 0 && n < MAX_INVENTORY);
701
702 if(!sd->inventory_data[n])
703 return 0;
704
705 if (!itemdb->isequip2(sd->inventory_data[n]))
706 return 0; //Not equippable by players.
707
708 ep = sd->inventory_data[n]->equip;
709 if (sd->inventory_data[n]->look == W_DAGGER
710 || sd->inventory_data[n]->look == W_1HSWORD
711 || sd->inventory_data[n]->look == W_1HAXE
712 ) {
713 if (pc->checkskill(sd,AS_LEFT) > 0
714 || (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN
715 || (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO
716 ) {
717 //Kagerou and Oboro can dual wield daggers. [Rytech]
718 if( ep == EQP_HAND_R )
719 return EQP_ARMS;
720 if( ep == EQP_SHADOW_WEAPON )
721 return EQP_SHADOW_ARMS;
722 }
723 }
724 return ep;
725}
726
727int pc_setinventorydata(struct map_session_data *sd)
728{
729 int i;
730
731 nullpo_ret(sd);
732
733 for (i = 0; i < MAX_INVENTORY; i++) {
734 int id = sd->status.inventory[i].nameid;
735 sd->inventory_data[i] = id?itemdb->search(id):NULL;
736 }
737 return 0;
738}
739
740int pc_calcweapontype(struct map_session_data *sd)
741{
742 nullpo_ret(sd);
743
744 // single-hand
745 if(sd->weapontype2 == W_FIST) {
746 sd->status.weapon = sd->weapontype1;
747 return 1;
748 }
749 if(sd->weapontype1 == W_FIST) {
750 sd->status.weapon = sd->weapontype2;
751 return 1;
752 }
753 // dual-wield
754 sd->status.weapon = 0;
755 switch (sd->weapontype1){
756 case W_DAGGER:
757 switch (sd->weapontype2) {
758 case W_DAGGER: sd->status.weapon = W_DOUBLE_DD; break;
759 case W_1HSWORD: sd->status.weapon = W_DOUBLE_DS; break;
760 case W_1HAXE: sd->status.weapon = W_DOUBLE_DA; break;
761 }
762 break;
763 case W_1HSWORD:
764 switch (sd->weapontype2) {
765 case W_DAGGER: sd->status.weapon = W_DOUBLE_DS; break;
766 case W_1HSWORD: sd->status.weapon = W_DOUBLE_SS; break;
767 case W_1HAXE: sd->status.weapon = W_DOUBLE_SA; break;
768 }
769 break;
770 case W_1HAXE:
771 switch (sd->weapontype2) {
772 case W_DAGGER: sd->status.weapon = W_DOUBLE_DA; break;
773 case W_1HSWORD: sd->status.weapon = W_DOUBLE_SA; break;
774 case W_1HAXE: sd->status.weapon = W_DOUBLE_AA; break;
775 }
776 }
777 // unknown, default to right hand type
778 if (!sd->status.weapon)
779 sd->status.weapon = sd->weapontype1;
780
781 return 2;
782}
783
784int pc_setequipindex(struct map_session_data *sd)
785{
786 int i,j;
787
788 nullpo_ret(sd);
789
790 for(i=0;i<EQI_MAX;i++)
791 sd->equip_index[i] = -1;
792
793 for(i=0;i<MAX_INVENTORY;i++) {
794 if(sd->status.inventory[i].nameid <= 0)
795 continue;
796 if(sd->status.inventory[i].equip) {
797 for(j=0;j<EQI_MAX;j++)
798 if(sd->status.inventory[i].equip & pc->equip_pos[j])
799 sd->equip_index[j] = i;
800
801 if(sd->status.inventory[i].equip & EQP_HAND_R)
802 {
803 if(sd->inventory_data[i])
804 sd->weapontype1 = sd->inventory_data[i]->look;
805 else
806 sd->weapontype1 = 0;
807 }
808
809 if( sd->status.inventory[i].equip & EQP_HAND_L )
810 {
811 if( sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON )
812 sd->weapontype2 = sd->inventory_data[i]->look;
813 else
814 sd->weapontype2 = 0;
815 }
816 }
817 }
818 pc->calcweapontype(sd);
819
820 return 0;
821}
822
823bool pc_isequipped(struct map_session_data *sd, int nameid)
824{
825 int i, j;
826
827 nullpo_retr(false, sd);
828 for (i = 0; i < EQI_MAX; i++) {
829 int index = sd->equip_index[i];
830 if( index < 0 ) continue;
831
832 if( i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index ) continue;
833 if( i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index ) continue;
834 if( i == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index) ) continue;
835
836 if( !sd->inventory_data[index] ) continue;
837
838 if( sd->inventory_data[index]->nameid == nameid )
839 return true;
840
841 for( j = 0; j < sd->inventory_data[index]->slot; j++ )
842 if( sd->status.inventory[index].card[j] == nameid )
843 return true;
844 }
845
846 return false;
847}
848
849bool pc_can_Adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd )
850{
851 if( !p1_sd || !p2_sd || !b_sd )
852 return false;
853
854 if( b_sd->status.father || b_sd->status.mother || b_sd->adopt_invite )
855 return false; // already adopted baby / in adopt request
856
857 if( !p1_sd->status.partner_id || !p1_sd->status.party_id || p1_sd->status.party_id != b_sd->status.party_id )
858 return false; // You need to be married and in party with baby to adopt
859
860 if( p1_sd->status.partner_id != p2_sd->status.char_id || p2_sd->status.partner_id != p1_sd->status.char_id )
861 return false; // Not married, wrong married
862
863 if( p2_sd->status.party_id != p1_sd->status.party_id )
864 return false; // Both parents need to be in the same party
865
866 // Parents need to have their ring equipped
867 if( !pc->isequipped(p1_sd, WEDDING_RING_M) && !pc->isequipped(p1_sd, WEDDING_RING_F) )
868 return false;
869
870 if( !pc->isequipped(p2_sd, WEDDING_RING_M) && !pc->isequipped(p2_sd, WEDDING_RING_F) )
871 return false;
872
873 // Already adopted a baby
874 if( p1_sd->status.child || p2_sd->status.child ) {
875 clif->adopt_reply(p1_sd, 0);
876 return false;
877 }
878
879 // Parents need at least lvl 70 to adopt
880 if( p1_sd->status.base_level < 70 || p2_sd->status.base_level < 70 ) {
881 clif->adopt_reply(p1_sd, 1);
882 return false;
883 }
884
885 if( b_sd->status.partner_id ) {
886 clif->adopt_reply(p1_sd, 2);
887 return false;
888 }
889
890 if( !( ( b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF ) || b_sd->status.class_ == JOB_SUPER_NOVICE ) )
891 return false;
892
893 return true;
894}
895
896/*==========================================
897 * Adoption Process
898 *------------------------------------------*/
899bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd)
900{
901 int job, joblevel;
902 unsigned int jobexp;
903
904 if( !pc->can_Adopt(p1_sd, p2_sd, b_sd) )
905 return false;
906
907 nullpo_retr(false, b_sd);
908 // Preserve current job levels and progress
909 joblevel = b_sd->status.job_level;
910 jobexp = b_sd->status.job_exp;
911
912 job = pc->mapid2jobid(b_sd->class_|JOBL_BABY, b_sd->status.sex);
913 if( job != -1 && !pc->jobchange(b_sd, job, 0) )
914 { // Success, proceed to configure parents and baby skills
915 p1_sd->status.child = b_sd->status.char_id;
916 p2_sd->status.child = b_sd->status.char_id;
917 b_sd->status.father = p1_sd->status.char_id;
918 b_sd->status.mother = p2_sd->status.char_id;
919
920 // Restore progress
921 b_sd->status.job_level = joblevel;
922 clif->updatestatus(b_sd, SP_JOBLEVEL);
923 b_sd->status.job_exp = jobexp;
924 clif->updatestatus(b_sd, SP_JOBEXP);
925
926 // Baby Skills
927 pc->skill(b_sd, WE_BABY, 1, SKILL_GRANT_PERMANENT);
928 pc->skill(b_sd, WE_CALLPARENT, 1, SKILL_GRANT_PERMANENT);
929
930 // Parents Skills
931 pc->skill(p1_sd, WE_CALLBABY, 1, SKILL_GRANT_PERMANENT);
932 pc->skill(p2_sd, WE_CALLBABY, 1, SKILL_GRANT_PERMANENT);
933
934 return true;
935 }
936
937 return false; // Job Change Fail
938}
939
940/*=================================================
941 * Checks if the player can equip the item at index n in inventory.
942 * Returns 0 (no) or 1 (yes).
943 *------------------------------------------------*/
944int pc_isequip(struct map_session_data *sd,int n)
945{
946 struct item_data *item;
947
948 nullpo_ret(sd);
949
950 item = sd->inventory_data[n];
951
952 if(item == NULL)
953 return 0;
954
955#if PACKETVER <= 20100707
956 if (itemdb_is_shadowequip(item->equip) || itemdb_is_costumeequip(item->equip))
957 return 0;
958#endif
959
960 if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT))
961 return 1;
962
963 if (item->elv && sd->status.base_level < item->elv) {
964 clif->msgtable(sd, MSG_ITEM_CANT_EQUIP_LVL);
965 return 0;
966 }
967 if (item->elvmax && sd->status.base_level > item->elvmax) {
968 clif->msgtable(sd, MSG_ITEM_CANT_EQUIP_LVL);
969 return 0;
970 }
971 if(item->sex != 2 && sd->status.sex != item->sex)
972 return 0;
973
974 if ( item->equip & EQP_AMMO ) {
975 if ( (sd->state.active && !pc_iscarton(sd)) // check if sc data is already loaded.
976 && (sd->status.class_ == JOB_GENETIC_T || sd->status.class_ == JOB_GENETIC) ) {
977 clif->msgtable(sd, MSG_ITEM_NEED_CART);
978 return 0;
979 }
980 if ( !pc_ismadogear(sd) && (sd->status.class_ == JOB_MECHANIC_T || sd->status.class_ == JOB_MECHANIC) ) {
981 clif->msgtable(sd, MSG_ITEM_NEED_MADO);
982 return 0;
983 }
984 }
985 if (sd->sc.count) {
986
987 if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_NOEQUIPWEAPON]) // Also works with left-hand weapons [DracoRPG]
988 return 0;
989 if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_NOEQUIPSHIELD])
990 return 0;
991 if(item->equip & EQP_ARMOR && sd->sc.data[SC_NOEQUIPARMOR])
992 return 0;
993 if(item->equip & EQP_HEAD_TOP && sd->sc.data[SC_NOEQUIPHELM])
994 return 0;
995 if(item->equip & EQP_ACC && sd->sc.data[SC__STRIPACCESSARY])
996 return 0;
997 if(item->equip && sd->sc.data[SC_KYOUGAKU])
998 return 0;
999
1000 if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SUPERNOVICE) {
1001 //Spirit of Super Novice equip bonuses. [Skotlex]
1002 if (sd->status.base_level > 90 && item->equip & EQP_HELM)
1003 return 1; //Can equip all helms
1004
1005 if (sd->status.base_level > 96 && item->equip & EQP_ARMS && item->type == IT_WEAPON)
1006 switch(item->look) { //In weapons, the look determines type of weapon.
1007 case W_DAGGER: //Level 4 Knives are equippable.. this means all knives, I'd guess?
1008 case W_1HSWORD: //All 1H swords
1009 case W_1HAXE: //All 1H Axes
1010 case W_MACE: //All 1H Maces
1011 case W_STAFF: //All 1H Staves
1012 return 1;
1013 }
1014 }
1015 }
1016 //Not equipable by class. [Skotlex]
1017 if (!(1ULL<<(sd->class_&MAPID_BASEMASK)&item->class_base[(sd->class_&JOBL_2_1)?1:((sd->class_&JOBL_2_2)?2:0)]))
1018 return 0;
1019 //Not usable by upper class. [Inkfish]
1020 while( 1 ) {
1021 if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
1022 if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
1023 if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY ) break;
1024 if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD ) break;
1025 return 0;
1026 }
1027
1028 if ( battle_config.unequip_restricted_equipment & 1 ) {
1029 int i;
1030 for ( i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++ )
1031 if ( map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].nameid )
1032 return 0;
1033 }
1034
1035 if ( battle_config.unequip_restricted_equipment & 2 ) {
1036 if ( !itemdb_isspecial( sd->status.inventory[n].card[0] ) ) {
1037 int i, slot;
1038 for ( slot = 0; slot < MAX_SLOTS; slot++ )
1039 for ( i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++ )
1040 if ( map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].card[slot] )
1041 return 0;
1042 }
1043 }
1044
1045 return 1;
1046}
1047
1048/*==========================================
1049 * No problem with the session id
1050 * set the status that has been sent from char server
1051 *------------------------------------------*/
1052bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, const struct mmo_charstatus *st, bool changing_mapservers)
1053{
1054 int i;
1055 int64 tick = timer->gettick();
1056 uint32 ip;
1057
1058 nullpo_retr(false, sd);
1059 ip = sockt->session[sd->fd]->client_addr;
1060
1061 sd->login_id2 = login_id2;
1062
1063 if (pc->set_group(sd, group_id) != 0) {
1064 ShowWarning("pc_authok: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
1065 st->name, sd->status.account_id, group_id);
1066 clif->authfail_fd(sd->fd, 0);
1067 return false;
1068 }
1069
1070 memcpy(&sd->status, st, sizeof(*st));
1071
1072 if (st->sex != sd->status.sex) {
1073 clif->authfail_fd(sd->fd, 0);
1074 return false;
1075 }
1076
1077 //Set the map-server used job id. [Skotlex]
1078 i = pc->jobid2mapid(sd->status.class_);
1079 if (i == -1) { //Invalid class?
1080 ShowError("pc_authok: Invalid class %d for player %s (%d:%d). Class was changed to novice.\n", sd->status.class_, sd->status.name, sd->status.account_id, sd->status.char_id);
1081 sd->status.class_ = JOB_NOVICE;
1082 sd->class_ = MAPID_NOVICE;
1083 } else
1084 sd->class_ = i;
1085
1086 // Checks and fixes to character status data, that are required
1087 // in case of configuration change or stuff, which cannot be
1088 // checked on char-server.
1089 if( sd->status.hair < MIN_HAIR_STYLE || sd->status.hair > MAX_HAIR_STYLE ) {
1090 sd->status.hair = MIN_HAIR_STYLE;
1091 }
1092 if( sd->status.hair_color < MIN_HAIR_COLOR || sd->status.hair_color > MAX_HAIR_COLOR ) {
1093 sd->status.hair_color = MIN_HAIR_COLOR;
1094 }
1095 if( sd->status.clothes_color < MIN_CLOTH_COLOR || sd->status.clothes_color > MAX_CLOTH_COLOR ) {
1096 sd->status.clothes_color = MIN_CLOTH_COLOR;
1097 }
1098 if (sd->status.body < MIN_BODY_STYLE || sd->status.body > MAX_BODY_STYLE) {
1099 sd->status.body = MIN_BODY_STYLE;
1100 }
1101
1102 //Initializations to null/0 unneeded since map_session_data was filled with 0 upon allocation.
1103 if(!sd->status.hp) pc_setdead(sd);
1104 sd->state.connect_new = 1;
1105
1106 sd->followtimer = INVALID_TIMER; // [MouseJstr]
1107 sd->invincible_timer = INVALID_TIMER;
1108 sd->npc_timer_id = INVALID_TIMER;
1109 sd->pvp_timer = INVALID_TIMER;
1110 sd->fontcolor_tid = INVALID_TIMER;
1111 sd->expiration_tid = INVALID_TIMER;
1112 /**
1113 * For the Secure NPC Timeout option (check config/Secure.h) [RR]
1114 **/
1115#ifdef SECURE_NPCTIMEOUT
1116 /**
1117 * Initialize to defaults/expected
1118 **/
1119 sd->npc_idle_timer = INVALID_TIMER;
1120 sd->npc_idle_tick = tick;
1121 sd->npc_idle_type = NPCT_INPUT;
1122#endif
1123
1124 sd->canuseitem_tick = tick;
1125 sd->canusecashfood_tick = tick;
1126 sd->canequip_tick = tick;
1127 sd->cantalk_tick = tick;
1128 sd->canskill_tick = tick;
1129 sd->cansendmail_tick = tick;
1130 sd->hchsysch_tick = tick;
1131
1132 sd->idletime = sockt->last_tick;
1133
1134 for(i = 0; i < MAX_SPIRITBALL; i++)
1135 sd->spirit_timer[i] = INVALID_TIMER;
1136 for(i = 0; i < ARRAYLENGTH(sd->autobonus); i++)
1137 sd->autobonus[i].active = INVALID_TIMER;
1138 for(i = 0; i < ARRAYLENGTH(sd->autobonus2); i++)
1139 sd->autobonus2[i].active = INVALID_TIMER;
1140 for(i = 0; i < ARRAYLENGTH(sd->autobonus3); i++)
1141 sd->autobonus3[i].active = INVALID_TIMER;
1142
1143 if (battle_config.item_auto_get)
1144 sd->state.autoloot = 10000;
1145
1146 if (battle_config.disp_experience)
1147 sd->state.showexp = 1;
1148 if (battle_config.disp_zeny)
1149 sd->state.showzeny = 1;
1150
1151 if (!(battle_config.display_skill_fail&2))
1152 sd->state.showdelay = 1;
1153
1154 pc->setinventorydata(sd);
1155 pc_setequipindex(sd);
1156
1157 if( sd->status.option & OPTION_INVISIBLE && !pc->can_use_command(sd, "@hide") )
1158 sd->status.option &=~ OPTION_INVISIBLE;
1159
1160 status->change_init(&sd->bl);
1161
1162 sd->sc.option = sd->status.option; //This is the actual option used in battle.
1163
1164 //Set here because we need the inventory data for weapon sprite parsing.
1165 status->set_viewdata(&sd->bl, sd->status.class_);
1166 unit->dataset(&sd->bl);
1167
1168 sd->guild_x = -1;
1169 sd->guild_y = -1;
1170
1171 sd->disguise = -1;
1172
1173 sd->instance = NULL;
1174 sd->instances = 0;
1175
1176 sd->bg_queue.arena = NULL;
1177 sd->bg_queue.ready = 0;
1178 sd->bg_queue.client_has_bg_data = 0;
1179 sd->bg_queue.type = 0;
1180
1181 VECTOR_INIT(sd->script_queues);
1182
1183 sd->state.dialog = 0;
1184
1185 sd->delayed_damage = 0;
1186
1187 if( battle_config.item_check )
1188 sd->state.itemcheck = 1;
1189
1190 // Event Timers
1191 for( i = 0; i < MAX_EVENTTIMER; i++ )
1192 sd->eventtimer[i] = INVALID_TIMER;
1193 // Rental Timer
1194 sd->rental_timer = INVALID_TIMER;
1195
1196 for( i = 0; i < MAX_PC_FEELHATE; i++ )
1197 sd->hate_mob[i] = -1;
1198
1199 sd->quest_log = NULL;
1200 sd->num_quests = 0;
1201 sd->avail_quests = 0;
1202 sd->save_quest = false;
1203
1204 sd->regs.vars = i64db_alloc(DB_OPT_BASE);
1205 sd->regs.arrays = NULL;
1206 sd->vars_dirty = false;
1207 sd->vars_ok = false;
1208 sd->vars_received = 0x0;
1209
1210 sd->lang_id = map->default_lang_id;
1211
1212 //warp player
1213 if ((i=pc->setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) {
1214 ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i);
1215
1216 // try warping to a default map instead (church graveyard)
1217 if (pc->setpos(sd, mapindex->name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) {
1218 // if we fail again
1219 clif->authfail_fd(sd->fd, 0);
1220 return false;
1221 }
1222 } else if (map->getcell(map->mapindex2mapid(sd->status.last_point.map), &sd->bl, sd->status.last_point.x, sd->status.last_point.y, CELL_CHKNOPASS)) {
1223 //warp player stuck in invaild cell
1224 pc->setpos(sd,sd->status.last_point.map,0,0,CLR_OUTSIGHT);
1225 }
1226
1227 clif->authok(sd);
1228
1229 //Prevent S. Novices from getting the no-death bonus just yet. [Skotlex]
1230 sd->die_counter=-1;
1231
1232 //display login notice
1233 ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in."
1234 " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"',"
1235 " IP: '"CL_WHITE"%u.%u.%u.%u"CL_RESET"',"
1236 " Group '"CL_WHITE"%d"CL_RESET"').\n",
1237 sd->status.name, sd->status.account_id, sd->status.char_id,
1238 CONVIP(ip), sd->group_id);
1239 // Send friends list
1240 clif->friendslist_send(sd);
1241
1242 if( !changing_mapservers ) {
1243
1244 if (battle_config.display_version == 1) {
1245 char buf[256];
1246 sprintf(buf, msg_sd(sd,1295), sysinfo->vcstype(), sysinfo->vcsrevision_src(), sysinfo->vcsrevision_scripts()); // %s revision '%s' (src) / '%s' (scripts)
1247 clif->message(sd->fd, buf);
1248 }
1249
1250 if (expiration_time != 0) {
1251 sd->expiration_time = expiration_time;
1252 }
1253
1254 /**
1255 * Fixes login-without-aura glitch (the screen won't blink at this point, don't worry :P)
1256 **/
1257 clif->changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y);
1258 }
1259
1260 /**
1261 * Check if player have any cool downs on
1262 **/
1263 skill->cooldown_load(sd);
1264
1265 /**
1266 * Check if player have any item cooldowns on
1267 **/
1268 pc->itemcd_do(sd,true);
1269
1270#ifdef GP_BOUND_ITEMS
1271 if( sd->status.party_id == 0 )
1272 pc->bound_clear(sd,IBT_PARTY);
1273#endif
1274
1275 /* [Ind/Hercules] */
1276 sd->sc_display = NULL;
1277 sd->sc_display_count = 0;
1278
1279 // Request all registries (auth is considered completed whence they arrive)
1280 intif->request_registry(sd,7);
1281 return true;
1282}
1283
1284/*==========================================
1285 * Closes a connection because it failed to be authenticated from the char server.
1286 *------------------------------------------*/
1287void pc_authfail(struct map_session_data *sd)
1288{
1289 nullpo_retv(sd);
1290 clif->authfail_fd(sd->fd, 0);
1291 return;
1292}
1293
1294//Attempts to set a mob.
1295int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl)
1296{
1297 int class_;
1298 if (!sd || !bl || pos < 0 || pos >= MAX_PC_FEELHATE)
1299 return 0;
1300 if (sd->hate_mob[pos] != -1) {
1301 //Can't change hate targets.
1302 clif->hate_info(sd, pos, sd->hate_mob[pos], 0); //Display current
1303 return 0;
1304 }
1305
1306 class_ = status->get_class(bl);
1307 if (!pc->db_checkid(class_)) {
1308 unsigned int max_hp = status_get_max_hp(bl);
1309 if ((pos == 1 && max_hp < 6000) || (pos == 2 && max_hp < 20000))
1310 return 0;
1311 if (pos != status_get_size(bl))
1312 return 0; //Wrong size
1313 }
1314 sd->hate_mob[pos] = class_;
1315 pc_setglobalreg(sd,script->add_str(pc->sg_info[pos].hate_var),class_+1);
1316 clif->hate_info(sd, pos, class_, 1);
1317 return 1;
1318}
1319
1320/*==========================================
1321 * Invoked once after the char/account/account2 registry variables are received. [Skotlex]
1322 *------------------------------------------*/
1323int pc_reg_received(struct map_session_data *sd)
1324{
1325 int i, idx = 0;
1326
1327 nullpo_ret(sd);
1328 sd->vars_ok = true;
1329
1330 sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level"));
1331 sd->change_level_3rd = pc_readglobalreg(sd,script->add_str("jobchange_level_3rd"));
1332 sd->die_counter = pc_readglobalreg(sd,script->add_str("PC_DIE_COUNTER"));
1333
1334 // Cash shop
1335 sd->cashPoints = pc_readaccountreg(sd,script->add_str("#CASHPOINTS"));
1336 sd->kafraPoints = pc_readaccountreg(sd,script->add_str("#KAFRAPOINTS"));
1337
1338 // Cooking Exp
1339 sd->cook_mastery = pc_readglobalreg(sd,script->add_str("COOK_MASTERY"));
1340
1341 if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) {
1342 // Better check for class rather than skill to prevent "skill resets" from unsetting this
1343 sd->mission_mobid = pc_readglobalreg(sd,script->add_str("TK_MISSION_ID"));
1344 sd->mission_count = pc_readglobalreg(sd,script->add_str("TK_MISSION_COUNT"));
1345 }
1346
1347 //SG map and mob read [Komurka]
1348 for (i = 0; i < MAX_PC_FEELHATE; i++) {
1349 //for now - someone need to make reading from txt/sql
1350 int j = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].feel_var));
1351 if (j != 0) {
1352 sd->feel_map[i].index = j;
1353 sd->feel_map[i].m = map->mapindex2mapid(j);
1354 } else {
1355 sd->feel_map[i].index = 0;
1356 sd->feel_map[i].m = -1;
1357 }
1358 sd->hate_mob[i] = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].hate_var))-1;
1359 }
1360
1361 if ((i = pc->checkskill(sd,RG_PLAGIARISM)) > 0) {
1362 sd->cloneskill_id = pc_readglobalreg(sd,script->add_str("CLONE_SKILL"));
1363 if (sd->cloneskill_id > 0 && (idx = skill->get_index(sd->cloneskill_id)) > 0) {
1364 sd->status.skill[idx].id = sd->cloneskill_id;
1365 sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("CLONE_SKILL_LV"));
1366 if (sd->status.skill[idx].lv > i)
1367 sd->status.skill[idx].lv = i;
1368 sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED;
1369 }
1370 }
1371 if ((i = pc->checkskill(sd,SC_REPRODUCE)) > 0) {
1372 sd->reproduceskill_id = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL"));
1373 if( sd->reproduceskill_id > 0 && (idx = skill->get_index(sd->reproduceskill_id)) > 0) {
1374 sd->status.skill[idx].id = sd->reproduceskill_id;
1375 sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL_LV"));
1376 if( i < sd->status.skill[idx].lv)
1377 sd->status.skill[idx].lv = i;
1378 sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED;
1379 }
1380 }
1381
1382 //Weird... maybe registries were reloaded?
1383 if (sd->state.active)
1384 return 0;
1385 sd->state.active = 1;
1386
1387 if (sd->status.party_id)
1388 party->member_joined(sd);
1389 if (sd->status.guild_id)
1390 guild->member_joined(sd);
1391
1392 // pet
1393 if (sd->status.pet_id > 0)
1394 intif->request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
1395
1396 // Homunculus [albator]
1397 if( sd->status.hom_id > 0 )
1398 intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id);
1399 if( sd->status.mer_id > 0 )
1400 intif->mercenary_request(sd->status.mer_id, sd->status.char_id);
1401 if( sd->status.ele_id > 0 )
1402 intif->elemental_request(sd->status.ele_id, sd->status.char_id);
1403
1404 map->addiddb(&sd->bl);
1405 map->delnickdb(sd->status.char_id, sd->status.name);
1406 if (!chrif->auth_finished(sd))
1407 ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id);
1408
1409 pc->load_combo(sd);
1410
1411 status_calc_pc(sd,SCO_FIRST|SCO_FORCE);
1412 chrif->scdata_request(sd->status.account_id, sd->status.char_id);
1413
1414 intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
1415 intif->request_questlog(sd);
1416
1417 if (sd->state.connect_new == 0 && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually.
1418 sd->state.connect_new = 1;
1419 clif->pLoadEndAck(sd->fd, sd);
1420 }
1421
1422 if (pc_isinvisible(sd)) {
1423 sd->vd.class_ = INVISIBLE_CLASS;
1424 clif->message(sd->fd, msg_sd(sd,11)); // Invisible: On
1425 // decrement the number of pvp players on the map
1426 map->list[sd->bl.m].users_pvp--;
1427
1428 if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {// unregister the player for ranking
1429 timer->delete( sd->pvp_timer, pc->calc_pvprank_timer );
1430 sd->pvp_timer = INVALID_TIMER;
1431 }
1432 clif->changeoption(&sd->bl);
1433 }
1434
1435 if( npc->motd ) /* [Ind/Hercules] */
1436 script->run(npc->motd->u.scr.script, 0, sd->bl.id, npc->fake_nd->bl.id);
1437
1438 return 1;
1439}
1440
1441int pc_calc_skillpoint(struct map_session_data* sd) {
1442 int i,inf2,skill_point=0;
1443
1444 nullpo_ret(sd);
1445
1446 for (i = 1; i < MAX_SKILL; i++) {
1447 int skill_lv = pc->checkskill2(sd,i);
1448 if (skill_lv > 0) {
1449 inf2 = skill->dbs->db[i].inf2;
1450 if((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) &&
1451 !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL|INF2_GUILD_SKILL)) //Do not count wedding/link skills. [Skotlex]
1452 ) {
1453 if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT)
1454 skill_point += skill_lv;
1455 else if(sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0)
1456 skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
1457 }
1458 }
1459 }
1460
1461 return skill_point;
1462}
1463
1464/*==========================================
1465 * Calculation of skill level.
1466 *------------------------------------------*/
1467int pc_calc_skilltree(struct map_session_data *sd)
1468{
1469 int i,id=0,flag;
1470 int c=0;
1471
1472 nullpo_ret(sd);
1473 i = pc->calc_skilltree_normalize_job(sd);
1474 c = pc->mapid2jobid(i, sd->status.sex);
1475 if( c == -1 )
1476 { //Unable to normalize job??
1477 ShowError("pc_calc_skilltree: Unable to normalize job %d for character %s (%d:%d)\n", i, sd->status.name, sd->status.account_id, sd->status.char_id);
1478 return 1;
1479 }
1480 c = pc->class2idx(c);
1481
1482 for( i = 0; i < MAX_SKILL; i++ ) {
1483 if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these
1484 sd->status.skill[i].id = 0; //First clear skills.
1485 /* permanent skills that must be re-checked */
1486 if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) {
1487 switch( skill->dbs->db[i].nameid ) {
1488 case NV_TRICKDEAD:
1489 if( (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) {
1490 sd->status.skill[i].id = 0;
1491 sd->status.skill[i].lv = 0;
1492 sd->status.skill[i].flag = 0;
1493 }
1494 break;
1495 }
1496 }
1497 }
1498
1499 for( i = 0; i < MAX_SKILL; i++ ) {
1500 if( sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED )
1501 { // Restore original level of skills after deleting earned skills.
1502 sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
1503 sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
1504 }
1505
1506 if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill->dbs->db[i].nameid >= DC_HUMMING && skill->dbs->db[i].nameid <= DC_SERVICEFORYOU )
1507 { //Enable Bard/Dancer spirit linked skills.
1508 if( sd->status.sex )
1509 { //Link dancer skills to bard.
1510 // i can be < 8?
1511 if( sd->status.skill[i-8].lv < 10 )
1512 continue;
1513 sd->status.skill[i].id = skill->dbs->db[i].nameid;
1514 sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill
1515 sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
1516 } else { //Link bard skills to dancer.
1517 if( sd->status.skill[i].lv < 10 )
1518 continue;
1519 // i can be < 8?
1520 sd->status.skill[i-8].id = skill->dbs->db[i-8].nameid;
1521 sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill
1522 sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
1523 }
1524 }
1525 }
1526
1527 if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) {
1528 for( i = 0; i < MAX_SKILL; i++ ) {
1529 switch(skill->dbs->db[i].nameid) {
1530 /**
1531 * Dummy skills must be added here otherwise they'll be displayed in the,
1532 * skill tree and since they have no icons they'll give resource errors
1533 **/
1534 case SM_SELFPROVOKE:
1535 case AB_DUPLELIGHT_MELEE:
1536 case AB_DUPLELIGHT_MAGIC:
1537 case WL_CHAINLIGHTNING_ATK:
1538 case WL_TETRAVORTEX_FIRE:
1539 case WL_TETRAVORTEX_WATER:
1540 case WL_TETRAVORTEX_WIND:
1541 case WL_TETRAVORTEX_GROUND:
1542 case WL_SUMMON_ATK_FIRE:
1543 case WL_SUMMON_ATK_WIND:
1544 case WL_SUMMON_ATK_WATER:
1545 case WL_SUMMON_ATK_GROUND:
1546 case LG_OVERBRAND_BRANDISH:
1547 case LG_OVERBRAND_PLUSATK:
1548 continue;
1549 default:
1550 break;
1551 }
1552 if( skill->dbs->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL) )
1553 continue; //Only skills you can't have are npc/guild ones
1554 if( skill->dbs->db[i].max > 0 )
1555 sd->status.skill[i].id = skill->dbs->db[i].nameid;
1556 }
1557 return 0;
1558 }
1559
1560 do {
1561 flag = 0;
1562 for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++) {
1563 int idx = pc->skill_tree[c][i].idx;
1564 bool satisfied = true;
1565 if (sd->status.skill[idx].id > 0)
1566 continue; //Skill already known.
1567
1568 if (!battle_config.skillfree) {
1569 int j;
1570 for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[c][i].need); j++) {
1571 struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[c][i].need, j);
1572 int level;
1573 if (sd->status.skill[req->idx].id == 0
1574 || sd->status.skill[req->idx].flag == SKILL_FLAG_TEMPORARY
1575 || sd->status.skill[req->idx].flag == SKILL_FLAG_PLAGIARIZED)
1576 level = 0; //Not learned.
1577 else if (sd->status.skill[req->idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real learned level
1578 level = sd->status.skill[req->idx].flag - SKILL_FLAG_REPLACED_LV_0;
1579 else
1580 level = pc->checkskill2(sd, req->idx);
1581 if (level < req->lv) {
1582 satisfied = false;
1583 break;
1584 }
1585 }
1586 if (sd->status.job_level < (int)pc->skill_tree[c][i].joblv) {
1587 int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree
1588 if (jobid > -1) {
1589 if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited)
1590 satisfied = false; // job level requirement wasn't satisfied
1591 } else {
1592 satisfied = false;
1593 }
1594 }
1595 }
1596 if (satisfied) {
1597 int inf2 = skill->dbs->db[idx].inf2;
1598
1599 if(!sd->status.skill[idx].lv && (
1600 (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
1601 inf2&INF2_WEDDING_SKILL ||
1602 (inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SOULLINK])
1603 ))
1604 continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills.
1605
1606 sd->status.skill[idx].id = id;
1607
1608 if(inf2&INF2_SPIRIT_SKILL) { //Spirit skills cannot be learned, they will only show up on your tree when you get buffed.
1609 sd->status.skill[idx].lv = 1; // need to manually specify a skill level
1610 sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill.
1611 }
1612 flag = 1; // skill list has changed, perform another pass
1613 }
1614 }
1615 } while(flag);
1616
1617 //
1618 if( c > 0 && (sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && sd->status.skill_point == 0 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )
1619 {
1620 /* Taekwon Ranger Bonus Skill Tree
1621 ============================================
1622 - Grant All Taekwon Tree, but only as Bonus Skills in case they drop from ranking.
1623 - (c > 0) to avoid grant Novice Skill Tree in case of Skill Reset (need more logic)
1624 - (sd->status.skill_point == 0) to wait until all skill points are asigned to avoid problems with Job Change quest. */
1625
1626 for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) {
1627 int idx = pc->skill_tree[c][i].idx;
1628 if( (skill->dbs->db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) )
1629 continue; //Do not include Quest/Wedding skills.
1630
1631 if( sd->status.skill[idx].id == 0 ) {
1632 sd->status.skill[idx].id = id;
1633 sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; // So it is not saved, and tagged as a "bonus" skill.
1634 } else if( id != NV_BASIC ) {
1635 sd->status.skill[idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[idx].lv; // Remember original level
1636 }
1637
1638 sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_);
1639 }
1640 }
1641
1642 return 0;
1643}
1644
1645//Checks if you can learn a new skill after having leveled up a skill.
1646void pc_check_skilltree(struct map_session_data *sd, int skill_id)
1647{
1648 int i,id=0,flag;
1649 int c=0;
1650
1651 if(battle_config.skillfree)
1652 return; //Function serves no purpose if this is set
1653
1654 nullpo_retv(sd);
1655 i = pc->calc_skilltree_normalize_job(sd);
1656 c = pc->mapid2jobid(i, sd->status.sex);
1657 if (c == -1) { //Unable to normalize job??
1658 ShowError("pc_check_skilltree: Unable to normalize job %d for character %s (%d:%d)\n", i, sd->status.name, sd->status.account_id, sd->status.char_id);
1659 return;
1660 }
1661 c = pc->class2idx(c);
1662 do {
1663 flag = 0;
1664 for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++) {
1665 int j, idx = pc->skill_tree[c][i].idx;
1666 bool satisfied = true;
1667
1668 if (sd->status.skill[idx].id) //Already learned
1669 continue;
1670
1671 for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[c][i].need); j++) {
1672 struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[c][i].need, j);
1673 int level;
1674 if (sd->status.skill[req->idx].id == 0
1675 || sd->status.skill[req->idx].flag == SKILL_FLAG_TEMPORARY
1676 || sd->status.skill[req->idx].flag == SKILL_FLAG_PLAGIARIZED)
1677 level = 0; //Not learned.
1678 else if (sd->status.skill[req->idx].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level
1679 level = sd->status.skill[req->idx].flag - SKILL_FLAG_REPLACED_LV_0;
1680 else
1681 level = pc->checkskill2(sd,req->idx);
1682 if (level < req->lv) {
1683 satisfied = false;
1684 break;
1685 }
1686 }
1687 if (!satisfied)
1688 continue;
1689
1690 if (sd->status.job_level < (int)pc->skill_tree[c][i].joblv) {
1691 int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree
1692 if (jobid > -1) {
1693 if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited)
1694 continue;
1695 } else {
1696 continue;
1697 }
1698 }
1699
1700 j = skill->dbs->db[idx].inf2;
1701 if( !sd->status.skill[idx].lv && (
1702 (j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
1703 j&INF2_WEDDING_SKILL ||
1704 (j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SOULLINK])
1705 ) )
1706 continue; //Cannot be learned via normal means.
1707
1708 sd->status.skill[idx].id = id;
1709
1710 flag = 1;
1711 }
1712 } while(flag);
1713}
1714
1715// Make sure all the skills are in the correct condition
1716// before persisting to the backend.. [MouseJstr]
1717int pc_clean_skilltree(struct map_session_data *sd)
1718{
1719 int i;
1720 nullpo_ret(sd);
1721 for (i = 0; i < MAX_SKILL; i++){
1722 if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED) {
1723 sd->status.skill[i].id = 0;
1724 sd->status.skill[i].lv = 0;
1725 sd->status.skill[i].flag = 0;
1726 } else if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) {
1727 sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
1728 sd->status.skill[i].flag = 0;
1729 }
1730 }
1731
1732 return 0;
1733}
1734
1735int pc_calc_skilltree_normalize_job(struct map_session_data *sd)
1736{
1737 int skill_point, novice_skills;
1738 int c;
1739
1740 nullpo_ret(sd);
1741 c = sd->class_;
1742 if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL))
1743 return c;
1744
1745 skill_point = pc->calc_skillpoint(sd);
1746
1747 novice_skills = pc->max_level[pc->class2idx(JOB_NOVICE)][1] - 1;
1748
1749 sd->sktree.second = sd->sktree.third = 0;
1750
1751 // limit 1st class and above to novice job levels
1752 if(skill_point < novice_skills) {
1753 c = MAPID_NOVICE;
1754 }
1755 // limit 2nd class and above to first class job levels (super novices are exempt)
1756 else if ((sd->class_&JOBL_2) && (sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE)
1757 {
1758 // regenerate change_level_2nd
1759 if (sd->change_level_2nd == 0) {
1760 if (sd->class_&JOBL_THIRD) {
1761 // if neither 2nd nor 3rd jobchange levels are known, we have to assume a default for 2nd
1762 if (sd->change_level_3rd == 0) {
1763 sd->change_level_2nd = pc->max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1];
1764 } else {
1765 sd->change_level_2nd = 1 + skill_point + sd->status.skill_point
1766 - (sd->status.job_level - 1)
1767 - (sd->change_level_3rd - 1)
1768 - novice_skills;
1769 }
1770 } else {
1771 sd->change_level_2nd = 1 + skill_point + sd->status.skill_point
1772 - (sd->status.job_level - 1)
1773 - novice_skills;
1774
1775 }
1776
1777 pc_setglobalreg(sd, script->add_str("jobchange_level"), sd->change_level_2nd);
1778 }
1779
1780 if (skill_point < novice_skills + (sd->change_level_2nd - 1)) {
1781 c &= MAPID_BASEMASK;
1782 sd->sktree.second = ( novice_skills + (sd->change_level_2nd - 1) ) - skill_point;
1783 } else if(sd->class_&JOBL_THIRD) { // limit 3rd class to 2nd class/trans job levels
1784 // regenerate change_level_3rd
1785 if (sd->change_level_3rd == 0) {
1786 sd->change_level_3rd = 1 + skill_point + sd->status.skill_point
1787 - (sd->status.job_level - 1)
1788 - (sd->change_level_2nd - 1)
1789 - novice_skills;
1790 pc_setglobalreg(sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd);
1791 }
1792
1793 if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) {
1794 c &= MAPID_UPPERMASK;
1795 sd->sktree.third = (novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) - skill_point;
1796 }
1797 }
1798 }
1799
1800 // restore non-limiting flags
1801 c |= sd->class_&(JOBL_UPPER|JOBL_BABY);
1802
1803 return c;
1804}
1805
1806/*==========================================
1807 * Updates the weight status
1808 *------------------------------------------
1809 * 1: overweight 50%
1810 * 2: overweight 90%
1811 * It's assumed that SC_WEIGHTOVER50 and SC_WEIGHTOVER90 are only started/stopped here.
1812 */
1813int pc_updateweightstatus(struct map_session_data *sd)
1814{
1815 int old_overweight;
1816 int new_overweight;
1817
1818 nullpo_retr(1, sd);
1819
1820 old_overweight = (sd->sc.data[SC_WEIGHTOVER90]) ? 2 : (sd->sc.data[SC_WEIGHTOVER50]) ? 1 : 0;
1821 new_overweight = (pc_is90overweight(sd)) ? 2 : (pc_is50overweight(sd)) ? 1 : 0;
1822
1823 if( old_overweight == new_overweight )
1824 return 0; // no change
1825
1826 // stop old status change
1827 if( old_overweight == 1 )
1828 status_change_end(&sd->bl, SC_WEIGHTOVER50, INVALID_TIMER);
1829 else if( old_overweight == 2 )
1830 status_change_end(&sd->bl, SC_WEIGHTOVER90, INVALID_TIMER);
1831
1832 // start new status change
1833 if( new_overweight == 1 )
1834 sc_start(NULL,&sd->bl, SC_WEIGHTOVER50, 100, 0, 0);
1835 else if( new_overweight == 2 )
1836 sc_start(NULL,&sd->bl, SC_WEIGHTOVER90, 100, 0, 0);
1837
1838 // update overweight status
1839 sd->regen.state.overweight = new_overweight;
1840
1841 return 0;
1842}
1843
1844int pc_disguise(struct map_session_data *sd, int class_) {
1845 nullpo_ret(sd);
1846 if (class_ == -1 && sd->disguise == -1)
1847 return 0;
1848 if (class_ >= 0 && sd->disguise == class_)
1849 return 0;
1850
1851 if (pc_isinvisible(sd)) { //Character is invisible. Stealth class-change. [Skotlex]
1852 sd->disguise = class_; //viewdata is set on uncloaking.
1853 return 2;
1854 }
1855
1856 if (sd->bl.prev != NULL) {
1857 if( class_ == -1 && sd->disguise == sd->status.class_ ) {
1858 clif->clearunit_single(-sd->bl.id,CLR_OUTSIGHT,sd->fd);
1859 } else if ( class_ != sd->status.class_ ) {
1860 pc_stop_walking(sd, STOPWALKING_FLAG_NONE);
1861 clif->clearunit_area(&sd->bl, CLR_OUTSIGHT);
1862 }
1863 }
1864
1865 if (class_ == -1) {
1866 sd->disguise = -1;
1867 class_ = sd->status.class_;
1868 } else
1869 sd->disguise = class_;
1870
1871 status->set_viewdata(&sd->bl, class_);
1872 clif->changeoption(&sd->bl);
1873 // We need to update the client so it knows that a costume is being used
1874 if( sd->sc.option&OPTION_COSTUME ) {
1875 clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_);
1876 clif->changelook(&sd->bl,LOOK_WEAPON,0);
1877 clif->changelook(&sd->bl,LOOK_SHIELD,0);
1878 clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
1879 }
1880
1881 if (sd->bl.prev != NULL) {
1882 clif->spawn(&sd->bl);
1883 if (class_ == sd->status.class_ && pc_iscarton(sd)) {
1884 //It seems the cart info is lost on undisguise.
1885 clif->cartlist(sd);
1886 clif->updatestatus(sd,SP_CARTINFO);
1887 }
1888 if (sd->chat_id != 0) {
1889 struct chat_data *cd = map->id2cd(sd->chat_id);
1890
1891 if (cd != NULL)
1892 clif->dispchat(cd,0);
1893 }
1894 }
1895 return 1;
1896}
1897
1898int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id)
1899{
1900 int i;
1901
1902 if( !rate )
1903 return 0;
1904
1905 nullpo_ret(spell);
1906 Assert_ret(max <= 15); // autospell array size
1907 for( i = 0; i < max && spell[i].id; i++ )
1908 {
1909 if( (spell[i].card_id == card_id || spell[i].rate < 0 || rate < 0) && spell[i].id == id && spell[i].lv == lv )
1910 {
1911 if( !battle_config.autospell_stacking && spell[i].rate > 0 && rate > 0 )
1912 return 0;
1913 rate += spell[i].rate;
1914 break;
1915 }
1916 }
1917 if (i == max) {
1918 ShowWarning("pc_bonus: Reached max (%d) number of autospells per character!\n", max);
1919 return 0;
1920 }
1921 spell[i].id = id;
1922 spell[i].lv = lv;
1923 spell[i].rate = rate;
1924 //Auto-update flag value.
1925 if (!(flag&BF_RANGEMASK)) flag|=BF_SHORT|BF_LONG; //No range defined? Use both.
1926 if (!(flag&BF_WEAPONMASK)) flag|=BF_WEAPON; //No attack type defined? Use weapon.
1927 if (!(flag&BF_SKILLMASK)) {
1928 if (flag&(BF_MAGIC|BF_MISC)) flag|=BF_SKILL; //These two would never trigger without BF_SKILL
1929 if (flag&BF_WEAPON) flag|=BF_NORMAL; //By default autospells should only trigger on normal weapon attacks.
1930 }
1931 spell[i].flag|= flag;
1932 spell[i].card_id = card_id;
1933 return 1;
1934}
1935
1936int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id)
1937{
1938 int i;
1939
1940 if( !rate )
1941 return 0;
1942
1943 nullpo_ret(spell);
1944 Assert_ret(max <= 15); // autospell array size
1945 for( i = 0; i < max && spell[i].id; i++ )
1946 {
1947 ; // each autospell works independently
1948 }
1949
1950 if( i == max )
1951 {
1952 ShowWarning("pc_bonus: Reached max (%d) number of autospells per character!\n", max);
1953 return 0;
1954 }
1955
1956 spell[i].flag = src_skill;
1957 spell[i].id = id;
1958 spell[i].lv = lv;
1959 spell[i].rate = rate;
1960 spell[i].card_id = card_id;
1961 return 1;
1962}
1963
1964/**
1965 * Adds an AddEff/AddEff2/AddEffWhenHit bonus to a character.
1966 *
1967 * @param effect Effects array to append to.
1968 * @param max Size of the effect array.
1969 * @param id Effect ID (@see enum sc_type).
1970 * @param rate Trigger rate.
1971 * @param arrow_rate Trigger rate modifier for ranged attacks (adds to the base rate).
1972 * @param flag Trigger flags (@see enum auto_trigger_flag).
1973 * @param duration Fixed (non-reducible) duration in ms. If 0, uses the default (reducible) duration of the given effect.
1974 * @retval 1 on success.
1975 * @retval 0 on failure.
1976 */
1977int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, int16 rate, int16 arrow_rate, uint8 flag, uint16 duration)
1978{
1979 int i;
1980
1981 nullpo_ret(effect);
1982 if (!(flag&(ATF_SHORT|ATF_LONG)))
1983 flag|=ATF_SHORT|ATF_LONG; //Default range: both
1984 if (!(flag&(ATF_TARGET|ATF_SELF)))
1985 flag|=ATF_TARGET; //Default target: enemy.
1986 if (!(flag&(ATF_WEAPON|ATF_MAGIC|ATF_MISC)))
1987 flag|=ATF_WEAPON; //Default type: weapon.
1988
1989 for (i = 0; i < max && effect[i].flag; i++) {
1990 // Update existing effect if any.
1991 if (effect[i].id == id && effect[i].flag == flag && effect[i].duration == duration) {
1992 effect[i].rate += rate;
1993 effect[i].arrow_rate += arrow_rate;
1994 return 1;
1995 }
1996 }
1997 if (i == max) {
1998 ShowWarning("pc_bonus: Reached max (%d) number of add effects per character!\n", max);
1999 return 0;
2000 }
2001 effect[i].id = id;
2002 effect[i].rate = rate;
2003 effect[i].arrow_rate = arrow_rate;
2004 effect[i].flag = flag;
2005 effect[i].duration = duration;
2006 return 1;
2007}
2008
2009int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill_id, unsigned char target) {
2010 int i;
2011
2012 nullpo_ret(effect);
2013 for( i = 0; i < max && effect[i].skill; i++ ) {
2014 if( effect[i].id == id && effect[i].skill == skill_id && effect[i].target == target ) {
2015 effect[i].rate += rate;
2016 return 1;
2017 }
2018 }
2019 if( i == max ) {
2020 ShowWarning("pc_bonus: Reached max (%d) number of add effects on skill per character!\n", max);
2021 return 0;
2022 }
2023 effect[i].id = id;
2024 effect[i].rate = rate;
2025 effect[i].skill = skill_id;
2026 effect[i].target = target;
2027 return 1;
2028}
2029
2030int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race_mask, int rate) {
2031 int i;
2032
2033 nullpo_ret(drop);
2034 //Apply config rate adjustment settings.
2035 if (rate >= 0) { //Absolute drop.
2036 if (battle_config.item_rate_adddrop != 100)
2037 rate = rate*battle_config.item_rate_adddrop/100;
2038 if (rate < battle_config.item_drop_adddrop_min)
2039 rate = battle_config.item_drop_adddrop_min;
2040 else if (rate > battle_config.item_drop_adddrop_max)
2041 rate = battle_config.item_drop_adddrop_max;
2042 } else { //Relative drop, max/min limits are applied at drop time.
2043 if (battle_config.item_rate_adddrop != 100)
2044 rate = rate*battle_config.item_rate_adddrop/100;
2045 if (rate > -1)
2046 rate = -1;
2047 }
2048 for(i = 0; i < max && (drop[i].id || drop[i].group); i++) {
2049 if (((id && drop[i].id == id) || (group && drop[i].group == group))
2050 && race_mask != RCMASK_NONE
2051 ) {
2052 drop[i].race |= race_mask;
2053 if (drop[i].rate > 0 && rate > 0) {
2054 //Both are absolute rates.
2055 if (drop[i].rate < rate)
2056 drop[i].rate = rate;
2057 } else
2058 if(drop[i].rate < 0 && rate < 0) {
2059 //Both are relative rates.
2060 if (drop[i].rate > rate)
2061 drop[i].rate = rate;
2062 } else if (rate < 0) //Give preference to relative rate.
2063 drop[i].rate = rate;
2064 return 1;
2065 }
2066 }
2067 if(i == max) {
2068 ShowWarning("pc_bonus: Reached max (%d) number of added drops per character!\n", max);
2069 return 0;
2070 }
2071 drop[i].id = id;
2072 drop[i].group = group;
2073 drop[i].race |= race_mask;
2074 drop[i].rate = rate;
2075 return 1;
2076}
2077
2078int pc_addautobonus(struct s_autobonus *bonus,char max,const char *bonus_script,short rate,unsigned int dur,short flag,const char *other_script,unsigned short pos,bool onskill) {
2079 int i;
2080
2081 nullpo_ret(bonus);
2082 nullpo_ret(bonus_script);
2083 ARR_FIND(0, max, i, bonus[i].rate == 0);
2084 if( i == max )
2085 {
2086 ShowWarning("pc_addautobonus: Reached max (%d) number of autobonus per character!\n", max);
2087 return 0;
2088 }
2089
2090 if( !onskill )
2091 {
2092 if( !(flag&BF_RANGEMASK) )
2093 flag|=BF_SHORT|BF_LONG; //No range defined? Use both.
2094 if( !(flag&BF_WEAPONMASK) )
2095 flag|=BF_WEAPON; //No attack type defined? Use weapon.
2096 if( !(flag&BF_SKILLMASK) )
2097 {
2098 if( flag&(BF_MAGIC|BF_MISC) )
2099 flag|=BF_SKILL; //These two would never trigger without BF_SKILL
2100 if( flag&BF_WEAPON )
2101 flag|=BF_NORMAL|BF_SKILL;
2102 }
2103 }
2104
2105 bonus[i].rate = rate;
2106 bonus[i].duration = dur;
2107 bonus[i].active = INVALID_TIMER;
2108 bonus[i].atk_type = flag;
2109 bonus[i].pos = pos;
2110 bonus[i].bonus_script = aStrdup(bonus_script);
2111 bonus[i].other_script = other_script?aStrdup(other_script):NULL;
2112 return 1;
2113}
2114
2115int pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,char max,bool restore)
2116{
2117 int i;
2118 nullpo_ret(sd);
2119 nullpo_ret(autobonus);
2120
2121 for( i = 0; i < max; i++ )
2122 {
2123 if( autobonus[i].active != INVALID_TIMER )
2124 {
2125 if( restore && sd->state.autobonus&autobonus[i].pos )
2126 {
2127 if( autobonus[i].bonus_script )
2128 {
2129 int j;
2130 ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos );
2131 if( j < EQI_MAX )
2132 script->run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]);
2133 }
2134 continue;
2135 }
2136 else
2137 { // Logout / Unequipped an item with an activated bonus
2138 timer->delete(autobonus[i].active,pc->endautobonus);
2139 autobonus[i].active = INVALID_TIMER;
2140 }
2141 }
2142
2143 if( autobonus[i].bonus_script ) aFree(autobonus[i].bonus_script);
2144 if( autobonus[i].other_script ) aFree(autobonus[i].other_script);
2145 autobonus[i].bonus_script = autobonus[i].other_script = NULL;
2146 autobonus[i].rate = autobonus[i].atk_type = autobonus[i].duration = autobonus[i].pos = 0;
2147 autobonus[i].active = INVALID_TIMER;
2148 }
2149
2150 return 0;
2151}
2152
2153int pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus)
2154{
2155 nullpo_ret(sd);
2156 nullpo_ret(autobonus);
2157
2158 if( autobonus->other_script )
2159 {
2160 int j;
2161 ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
2162 if( j < EQI_MAX )
2163 script->run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
2164 }
2165
2166 autobonus->active = timer->add(timer->gettick()+autobonus->duration, pc->endautobonus, sd->bl.id, (intptr_t)autobonus);
2167 sd->state.autobonus |= autobonus->pos;
2168 status_calc_pc(sd,SCO_NONE);
2169
2170 return 0;
2171}
2172
2173int pc_endautobonus(int tid, int64 tick, int id, intptr_t data) {
2174 struct map_session_data *sd = map->id2sd(id);
2175 struct s_autobonus *autobonus = (struct s_autobonus *)data;
2176
2177 nullpo_ret(sd);
2178 nullpo_ret(autobonus);
2179
2180 autobonus->active = INVALID_TIMER;
2181 sd->state.autobonus &= ~autobonus->pos;
2182 status_calc_pc(sd,SCO_NONE);
2183 return 0;
2184}
2185
2186int pc_bonus_addele(struct map_session_data* sd, unsigned char ele, short rate, short flag)
2187{
2188 int i;
2189 struct weapon_data* wd;
2190
2191 nullpo_ret(sd);
2192 wd = (sd->state.lr_flag ? &sd->left_weapon : &sd->right_weapon);
2193
2194 ARR_FIND(0, MAX_PC_BONUS, i, wd->addele2[i].rate == 0);
2195
2196 if (i == MAX_PC_BONUS)
2197 {
2198 ShowWarning("pc_addele: Reached max (%d) possible bonuses for this player.\n", MAX_PC_BONUS);
2199 return 0;
2200 }
2201
2202 if (!(flag&BF_RANGEMASK))
2203 flag |= BF_SHORT|BF_LONG;
2204 if (!(flag&BF_WEAPONMASK))
2205 flag |= BF_WEAPON;
2206 if (!(flag&BF_SKILLMASK))
2207 {
2208 if (flag&(BF_MAGIC|BF_MISC))
2209 flag |= BF_SKILL;
2210 if (flag&BF_WEAPON)
2211 flag |= BF_NORMAL|BF_SKILL;
2212 }
2213
2214 wd->addele2[i].ele = ele;
2215 wd->addele2[i].rate = rate;
2216 wd->addele2[i].flag = flag;
2217
2218 return 0;
2219}
2220
2221int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate, short flag)
2222{
2223 int i;
2224
2225 nullpo_ret(sd);
2226 ARR_FIND(0, MAX_PC_BONUS, i, sd->subele2[i].rate == 0);
2227
2228 if (i == MAX_PC_BONUS)
2229 {
2230 ShowWarning("pc_subele: Reached max (%d) possible bonuses for this player.\n", MAX_PC_BONUS);
2231 return 0;
2232 }
2233
2234 if (!(flag&BF_RANGEMASK))
2235 flag |= BF_SHORT|BF_LONG;
2236 if (!(flag&BF_WEAPONMASK))
2237 flag |= BF_WEAPON;
2238 if (!(flag&BF_SKILLMASK))
2239 {
2240 if (flag&(BF_MAGIC|BF_MISC))
2241 flag |= BF_SKILL;
2242 if (flag&BF_WEAPON)
2243 flag |= BF_NORMAL|BF_SKILL;
2244 }
2245
2246 sd->subele2[i].ele = ele;
2247 sd->subele2[i].rate = rate;
2248 sd->subele2[i].flag = flag;
2249
2250 return 0;
2251}
2252
2253/**
2254 * Loops through the fields in a race bitmask (enum RaceMask => enum Race)
2255 *
2256 * To be used in pc_bonus functions with races represented in array form.
2257 */
2258#define BONUS_FOREACH_RCARRAY_FROMMASK(loop_counter, mask) \
2259 for ((loop_counter) = RC_FORMLESS; (loop_counter) < RC_MAX; ++(loop_counter)) \
2260 if (((mask) & 1<<(loop_counter)) == RCMASK_NONE) { \
2261 continue; \
2262 } else
2263
2264/*==========================================
2265 * Add a bonus(type) to player sd
2266 *------------------------------------------*/
2267int pc_bonus(struct map_session_data *sd,int type,int val) {
2268 struct status_data *bst;
2269 int bonus;
2270 int i;
2271 nullpo_ret(sd);
2272
2273 bst = &sd->base_status;
2274
2275 switch(type){
2276 case SP_STR:
2277 case SP_AGI:
2278 case SP_VIT:
2279 case SP_INT:
2280 case SP_DEX:
2281 case SP_LUK:
2282 if(sd->state.lr_flag != 2)
2283 sd->param_bonus[type-SP_STR]+=val;
2284 break;
2285 case SP_ATK1:
2286 if(!sd->state.lr_flag) {
2287 bonus = bst->rhw.atk + val;
2288 bst->rhw.atk = cap_value(bonus, 0, USHRT_MAX);
2289 }
2290 else if(sd->state.lr_flag == 1) {
2291 bonus = bst->lhw.atk + val;
2292 bst->lhw.atk = cap_value(bonus, 0, USHRT_MAX);
2293 }
2294 break;
2295 case SP_ATK2:
2296 if(!sd->state.lr_flag) {
2297 bonus = bst->rhw.atk2 + val;
2298 bst->rhw.atk2 = cap_value(bonus, 0, USHRT_MAX);
2299 }
2300 else if(sd->state.lr_flag == 1) {
2301 bonus = bst->lhw.atk2 + val;
2302 bst->lhw.atk2 = cap_value(bonus, 0, USHRT_MAX);
2303 }
2304 break;
2305 case SP_BASE_ATK:
2306 if(sd->state.lr_flag != 2) {
2307#ifdef RENEWAL
2308 bst->equip_atk += val;
2309#else
2310 bonus = bst->batk + val;
2311 bst->batk = cap_value(bonus, 0, USHRT_MAX);
2312#endif
2313 }
2314 break;
2315 case SP_DEF1:
2316 if(sd->state.lr_flag != 2) {
2317 bonus = bst->def + val;
2318 #ifdef RENEWAL
2319 bst->def = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2320 #else
2321 bst->def = cap_value(bonus, CHAR_MIN, CHAR_MAX);
2322 #endif
2323 }
2324 break;
2325 case SP_DEF2:
2326 if(sd->state.lr_flag != 2) {
2327 bonus = bst->def2 + val;
2328 bst->def2 = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2329 }
2330 break;
2331 case SP_MDEF1:
2332 if(sd->state.lr_flag != 2) {
2333 bonus = bst->mdef + val;
2334 #ifdef RENEWAL
2335 bst->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2336 #else
2337 bst->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX);
2338 #endif
2339 if( sd->state.lr_flag == 3 ) {//Shield, used for royal guard
2340 sd->bonus.shieldmdef += bonus;
2341 }
2342 }
2343 break;
2344 case SP_MDEF2:
2345 if(sd->state.lr_flag != 2) {
2346 bonus = bst->mdef2 + val;
2347 bst->mdef2 = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2348 }
2349 break;
2350 case SP_HIT:
2351 if(sd->state.lr_flag != 2) {
2352 bonus = bst->hit + val;
2353 bst->hit = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2354 } else
2355 sd->bonus.arrow_hit+=val;
2356 break;
2357 case SP_FLEE1:
2358 if(sd->state.lr_flag != 2) {
2359 bonus = bst->flee + val;
2360 bst->flee = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2361 }
2362 break;
2363 case SP_FLEE2:
2364 if(sd->state.lr_flag != 2) {
2365 bonus = bst->flee2 + val*10;
2366 bst->flee2 = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2367 }
2368 break;
2369 case SP_CRITICAL:
2370 if(sd->state.lr_flag != 2) {
2371 bonus = bst->cri + val*10;
2372 bst->cri = cap_value(bonus, SHRT_MIN, SHRT_MAX);
2373 } else
2374 sd->bonus.arrow_cri += val*10;
2375 break;
2376 case SP_ATKELE:
2377 if(val >= ELE_MAX) {
2378 ShowError("pc_bonus: SP_ATKELE: Invalid element %d\n", val);
2379 break;
2380 }
2381 switch (sd->state.lr_flag) {
2382 case 2:
2383 switch (sd->status.weapon) {
2384 case W_BOW:
2385 case W_REVOLVER:
2386 case W_RIFLE:
2387 case W_GATLING:
2388 case W_SHOTGUN:
2389 case W_GRENADE:
2390 //Become weapon element.
2391 bst->rhw.ele=val;
2392 break;
2393 default: //Become arrow element.
2394 sd->bonus.arrow_ele=val;
2395 break;
2396 }
2397 break;
2398 case 1:
2399 bst->lhw.ele=val;
2400 break;
2401 default:
2402 bst->rhw.ele=val;
2403 break;
2404 }
2405 break;
2406 case SP_DEFELE:
2407 if(val >= ELE_MAX) {
2408 ShowError("pc_bonus: SP_DEFELE: Invalid element %d\n", val);
2409 break;
2410 }
2411 if(sd->state.lr_flag != 2)
2412 bst->def_ele=val;
2413 break;
2414 case SP_MAXHP:
2415 if(sd->state.lr_flag == 2)
2416 break;
2417 val += (int)bst->max_hp;
2418 //Negative bonuses will underflow, this will be handled in status_calc_pc through casting
2419 //If this is called outside of status_calc_pc, you'd better pray they do not underflow and end with UINT_MAX max_hp.
2420 bst->max_hp = (unsigned int)val;
2421 break;
2422 case SP_MAXSP:
2423 if(sd->state.lr_flag == 2)
2424 break;
2425 val += (int)bst->max_sp;
2426 bst->max_sp = (unsigned int)val;
2427 break;
2428 #ifndef RENEWAL_CAST
2429 case SP_VARCASTRATE:
2430 #endif
2431 case SP_CASTRATE:
2432 if(sd->state.lr_flag != 2)
2433 sd->castrate+=val;
2434 break;
2435 case SP_MAXHPRATE:
2436 if(sd->state.lr_flag != 2)
2437 sd->hprate+=val;
2438 break;
2439 case SP_MAXSPRATE:
2440 if(sd->state.lr_flag != 2)
2441 sd->sprate+=val;
2442 break;
2443 case SP_SPRATE:
2444 if(sd->state.lr_flag != 2)
2445 sd->dsprate+=val;
2446 break;
2447 case SP_ATTACKRANGE:
2448 switch (sd->state.lr_flag) {
2449 case 2:
2450 switch (sd->status.weapon) {
2451 case W_BOW:
2452 case W_REVOLVER:
2453 case W_RIFLE:
2454 case W_GATLING:
2455 case W_SHOTGUN:
2456 case W_GRENADE:
2457 bst->rhw.range += val;
2458 }
2459 break;
2460 case 1:
2461 bst->lhw.range += val;
2462 break;
2463 default:
2464 bst->rhw.range += val;
2465 break;
2466 }
2467 break;
2468 case SP_SPEED_RATE: //Non stackable increase
2469 if(sd->state.lr_flag != 2)
2470 sd->bonus.speed_rate = min(sd->bonus.speed_rate, -val);
2471 break;
2472 case SP_SPEED_ADDRATE: //Stackable increase
2473 if(sd->state.lr_flag != 2)
2474 sd->bonus.speed_add_rate -= val;
2475 break;
2476 case SP_ASPD: //Raw increase
2477 if(sd->state.lr_flag != 2)
2478 sd->bonus.aspd_add -= 10*val;
2479 break;
2480 case SP_ASPD_RATE: //Stackable increase - Made it linear as per rodatazone
2481 if(sd->state.lr_flag != 2)
2482 #ifndef RENEWAL_ASPD
2483 bst->aspd_rate -= 10*val;
2484 #else
2485 bst->aspd_rate2 += val;
2486 #endif
2487 break;
2488 case SP_HP_RECOV_RATE:
2489 if(sd->state.lr_flag != 2)
2490 sd->hprecov_rate += val;
2491 break;
2492 case SP_SP_RECOV_RATE:
2493 if(sd->state.lr_flag != 2)
2494 sd->sprecov_rate += val;
2495 break;
2496 case SP_CRITICAL_DEF:
2497 if(sd->state.lr_flag != 2)
2498 sd->bonus.critical_def += val;
2499 break;
2500 case SP_NEAR_ATK_DEF:
2501 if(sd->state.lr_flag != 2)
2502 sd->bonus.near_attack_def_rate += val;
2503 break;
2504 case SP_LONG_ATK_DEF:
2505 if(sd->state.lr_flag != 2)
2506 sd->bonus.long_attack_def_rate += val;
2507 break;
2508 case SP_DOUBLE_RATE:
2509 if(sd->state.lr_flag == 0 && sd->bonus.double_rate < val)
2510 sd->bonus.double_rate = val;
2511 break;
2512 case SP_DOUBLE_ADD_RATE:
2513 if(sd->state.lr_flag == 0)
2514 sd->bonus.double_add_rate += val;
2515 break;
2516 case SP_MATK_RATE:
2517 if(sd->state.lr_flag != 2)
2518 sd->matk_rate += val;
2519 break;
2520 case SP_IGNORE_DEF_ELE:
2521 if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
2522 ShowError("pc_bonus: SP_IGNORE_DEF_ELE: Invalid element %d\n", val);
2523 break;
2524 }
2525 if ( val == ELE_ALL ) {
2526 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
2527 if(!sd->state.lr_flag)
2528 sd->right_weapon.ignore_def_ele |= 1<<i;
2529 else if(sd->state.lr_flag == 1)
2530 sd->left_weapon.ignore_def_ele |= 1<<i;
2531 }
2532 } else {
2533 if(!sd->state.lr_flag)
2534 sd->right_weapon.ignore_def_ele |= 1<<val;
2535 else if(sd->state.lr_flag == 1)
2536 sd->left_weapon.ignore_def_ele |= 1<<val;
2537 }
2538 break;
2539 case SP_IGNORE_DEF_RACE:
2540 {
2541 uint32 race_mask = map->race_id2mask(val);
2542 if (race_mask == RCMASK_NONE) {
2543 ShowWarning("pc_bonus: SP_IGNORE_DEF_RACE: Invalid Race (%d)\n", val);
2544 break;
2545 }
2546 if (!sd->state.lr_flag)
2547 sd->right_weapon.ignore_def_race |= race_mask;
2548 else if (sd->state.lr_flag == 1)
2549 sd->left_weapon.ignore_def_race |= race_mask;
2550 }
2551 break;
2552 case SP_ATK_RATE:
2553 if(sd->state.lr_flag != 2)
2554 sd->bonus.atk_rate += val;
2555 break;
2556 case SP_MAGIC_ATK_DEF:
2557 if(sd->state.lr_flag != 2)
2558 sd->bonus.magic_def_rate += val;
2559 break;
2560 case SP_MISC_ATK_DEF:
2561 if(sd->state.lr_flag != 2)
2562 sd->bonus.misc_def_rate += val;
2563 break;
2564 case SP_IGNORE_MDEF_RATE:
2565 if (sd->state.lr_flag != 2) {
2566 // Decomposed RC_ALL:
2567 sd->ignore_mdef[RC_NONBOSS] += val;
2568 sd->ignore_mdef[RC_BOSS] += val;
2569 }
2570 break;
2571 case SP_IGNORE_MDEF_ELE:
2572 if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
2573 ShowError("pc_bonus: SP_IGNORE_MDEF_ELE: Invalid element %d\n", val);
2574 break;
2575 }
2576 if (sd->state.lr_flag != 2) {
2577 if ( val == ELE_ALL ) {
2578 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
2579 sd->bonus.ignore_mdef_ele |= 1<<i;
2580 }
2581 } else {
2582 sd->bonus.ignore_mdef_ele |= 1<<val;
2583 }
2584 }
2585 break;
2586 case SP_IGNORE_MDEF_RACE:
2587 {
2588 uint32 race_mask = map->race_id2mask(val);
2589 if (race_mask == RCMASK_NONE) {
2590 ShowWarning("pc_bonus: SP_IGNORE_MDEF_RACE: Invalid Race (%d)\n", val);
2591 break;
2592 }
2593 if (sd->state.lr_flag != 2) {
2594 sd->bonus.ignore_mdef_race |= race_mask;
2595 }
2596 }
2597 break;
2598 case SP_PERFECT_HIT_RATE:
2599 if(sd->state.lr_flag != 2 && sd->bonus.perfect_hit < val)
2600 sd->bonus.perfect_hit = val;
2601 break;
2602 case SP_PERFECT_HIT_ADD_RATE:
2603 if(sd->state.lr_flag != 2)
2604 sd->bonus.perfect_hit_add += val;
2605 break;
2606 case SP_CRITICAL_RATE:
2607 if(sd->state.lr_flag != 2)
2608 sd->critical_rate+=val;
2609 break;
2610 case SP_DEF_RATIO_ATK_ELE:
2611 if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
2612 ShowError("pc_bonus: SP_DEF_RATIO_ATK_ELE: Invalid element %d\n", val);
2613 break;
2614 }
2615 if ( val == ELE_ALL ) {
2616 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
2617 if(!sd->state.lr_flag)
2618 sd->right_weapon.def_ratio_atk_ele |= 1<<i;
2619 else if(sd->state.lr_flag == 1)
2620 sd->left_weapon.def_ratio_atk_ele |= 1<<i;
2621 }
2622 } else {
2623 if(!sd->state.lr_flag)
2624 sd->right_weapon.def_ratio_atk_ele |= 1<<val;
2625 else if(sd->state.lr_flag == 1)
2626 sd->left_weapon.def_ratio_atk_ele |= 1<<val;
2627 }
2628 break;
2629 case SP_DEF_RATIO_ATK_RACE:
2630 {
2631 uint32 race_mask = map->race_id2mask(val);
2632 if (race_mask == RCMASK_NONE) {
2633 ShowWarning("pc_bonus: SP_DEF_RATIO_ATK_RACE: Invalid Race (%d)\n", val);
2634 break;
2635 }
2636 if (!sd->state.lr_flag)
2637 sd->right_weapon.def_ratio_atk_race |= race_mask;
2638 else if (sd->state.lr_flag == 1)
2639 sd->left_weapon.def_ratio_atk_race |= race_mask;
2640 }
2641 break;
2642 case SP_HIT_RATE:
2643 if(sd->state.lr_flag != 2)
2644 sd->hit_rate += val;
2645 break;
2646 case SP_FLEE_RATE:
2647 if(sd->state.lr_flag != 2)
2648 sd->flee_rate += val;
2649 break;
2650 case SP_FLEE2_RATE:
2651 if(sd->state.lr_flag != 2)
2652 sd->flee2_rate += val;
2653 break;
2654 case SP_DEF_RATE:
2655 if(sd->state.lr_flag != 2)
2656 sd->def_rate += val;
2657 break;
2658 case SP_DEF2_RATE:
2659 if(sd->state.lr_flag != 2)
2660 sd->def2_rate += val;
2661 break;
2662 case SP_MDEF_RATE:
2663 if(sd->state.lr_flag != 2)
2664 sd->mdef_rate += val;
2665 break;
2666 case SP_MDEF2_RATE:
2667 if(sd->state.lr_flag != 2)
2668 sd->mdef2_rate += val;
2669 break;
2670 case SP_RESTART_FULL_RECOVER:
2671 if(sd->state.lr_flag != 2)
2672 sd->special_state.restart_full_recover = 1;
2673 break;
2674 case SP_NO_CASTCANCEL:
2675 if(sd->state.lr_flag != 2)
2676 sd->special_state.no_castcancel = 1;
2677 break;
2678 case SP_NO_CASTCANCEL2:
2679 if(sd->state.lr_flag != 2)
2680 sd->special_state.no_castcancel2 = 1;
2681 break;
2682 case SP_NO_SIZEFIX:
2683 if(sd->state.lr_flag != 2)
2684 sd->special_state.no_sizefix = 1;
2685 break;
2686 case SP_NO_MAGIC_DAMAGE:
2687 if(sd->state.lr_flag == 2)
2688 break;
2689 val+= sd->special_state.no_magic_damage;
2690 sd->special_state.no_magic_damage = cap_value(val,0,100);
2691 break;
2692 case SP_NO_WEAPON_DAMAGE:
2693 if(sd->state.lr_flag == 2)
2694 break;
2695 val+= sd->special_state.no_weapon_damage;
2696 sd->special_state.no_weapon_damage = cap_value(val,0,100);
2697 break;
2698 case SP_NO_MISC_DAMAGE:
2699 if(sd->state.lr_flag == 2)
2700 break;
2701 val+= sd->special_state.no_misc_damage;
2702 sd->special_state.no_misc_damage = cap_value(val,0,100);
2703 break;
2704 case SP_NO_GEMSTONE:
2705 if(sd->state.lr_flag != 2)
2706 sd->special_state.no_gemstone = 1;
2707 break;
2708 case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG]
2709 if(sd->state.lr_flag != 2) {
2710 sd->special_state.intravision = 1;
2711 clif->status_change(&sd->bl, SI_CLAIRVOYANCE, 1, 0, 0, 0, 0);
2712 }
2713 break;
2714 case SP_NO_KNOCKBACK:
2715 if(sd->state.lr_flag != 2)
2716 sd->special_state.no_knockback = 1;
2717 break;
2718 case SP_SPLASH_RANGE:
2719 if(sd->bonus.splash_range < val)
2720 sd->bonus.splash_range = val;
2721 break;
2722 case SP_SPLASH_ADD_RANGE:
2723 sd->bonus.splash_add_range += val;
2724 break;
2725 case SP_SHORT_WEAPON_DAMAGE_RETURN:
2726 if(sd->state.lr_flag != 2)
2727 sd->bonus.short_weapon_damage_return += val;
2728 break;
2729 case SP_LONG_WEAPON_DAMAGE_RETURN:
2730 if(sd->state.lr_flag != 2)
2731 sd->bonus.long_weapon_damage_return += val;
2732 break;
2733 case SP_MAGIC_DAMAGE_RETURN: //AppleGirl Was Here
2734 if(sd->state.lr_flag != 2)
2735 sd->bonus.magic_damage_return += val;
2736 break;
2737 case SP_ALL_STATS: // [Valaris]
2738 if(sd->state.lr_flag!=2) {
2739 sd->param_bonus[SP_STR-SP_STR]+=val;
2740 sd->param_bonus[SP_AGI-SP_STR]+=val;
2741 sd->param_bonus[SP_VIT-SP_STR]+=val;
2742 sd->param_bonus[SP_INT-SP_STR]+=val;
2743 sd->param_bonus[SP_DEX-SP_STR]+=val;
2744 sd->param_bonus[SP_LUK-SP_STR]+=val;
2745 }
2746 break;
2747 case SP_AGI_VIT: // [Valaris]
2748 if(sd->state.lr_flag!=2) {
2749 sd->param_bonus[SP_AGI-SP_STR]+=val;
2750 sd->param_bonus[SP_VIT-SP_STR]+=val;
2751 }
2752 break;
2753 case SP_AGI_DEX_STR: // [Valaris]
2754 if(sd->state.lr_flag!=2) {
2755 sd->param_bonus[SP_AGI-SP_STR]+=val;
2756 sd->param_bonus[SP_DEX-SP_STR]+=val;
2757 sd->param_bonus[SP_STR-SP_STR]+=val;
2758 }
2759 break;
2760 case SP_PERFECT_HIDE: // [Valaris]
2761 if(sd->state.lr_flag!=2)
2762 sd->special_state.perfect_hiding=1;
2763 break;
2764 case SP_UNBREAKABLE:
2765 if(sd->state.lr_flag!=2)
2766 sd->bonus.unbreakable += val;
2767 break;
2768 case SP_UNBREAKABLE_WEAPON:
2769 if(sd->state.lr_flag != 2)
2770 sd->bonus.unbreakable_equip |= EQP_WEAPON;
2771 break;
2772 case SP_UNBREAKABLE_ARMOR:
2773 if(sd->state.lr_flag != 2)
2774 sd->bonus.unbreakable_equip |= EQP_ARMOR;
2775 break;
2776 case SP_UNBREAKABLE_HELM:
2777 if(sd->state.lr_flag != 2)
2778 sd->bonus.unbreakable_equip |= EQP_HELM;
2779 break;
2780 case SP_UNBREAKABLE_SHIELD:
2781 if(sd->state.lr_flag != 2)
2782 sd->bonus.unbreakable_equip |= EQP_SHIELD;
2783 break;
2784 case SP_UNBREAKABLE_GARMENT:
2785 if(sd->state.lr_flag != 2)
2786 sd->bonus.unbreakable_equip |= EQP_GARMENT;
2787 break;
2788 case SP_UNBREAKABLE_SHOES:
2789 if(sd->state.lr_flag != 2)
2790 sd->bonus.unbreakable_equip |= EQP_SHOES;
2791 break;
2792 case SP_CLASSCHANGE: // [Valaris]
2793 if(sd->state.lr_flag !=2)
2794 sd->bonus.classchange=val;
2795 break;
2796 case SP_LONG_ATK_RATE:
2797 if(sd->state.lr_flag != 2) //[Lupus] it should stack, too. As any other cards rate bonuses
2798 sd->bonus.long_attack_atk_rate+=val;
2799 break;
2800 case SP_BREAK_WEAPON_RATE:
2801 if(sd->state.lr_flag != 2)
2802 sd->bonus.break_weapon_rate+=val;
2803 break;
2804 case SP_BREAK_ARMOR_RATE:
2805 if(sd->state.lr_flag != 2)
2806 sd->bonus.break_armor_rate+=val;
2807 break;
2808 case SP_ADD_STEAL_RATE:
2809 if(sd->state.lr_flag != 2)
2810 sd->bonus.add_steal_rate+=val;
2811 break;
2812 case SP_DELAYRATE:
2813 if(sd->state.lr_flag != 2)
2814 sd->delayrate+=val;
2815 break;
2816 case SP_CRIT_ATK_RATE:
2817 if(sd->state.lr_flag != 2)
2818 sd->bonus.crit_atk_rate += val;
2819 break;
2820 case SP_NO_REGEN:
2821 if(sd->state.lr_flag != 2)
2822 sd->regen.state.block|=val;
2823 break;
2824 case SP_UNSTRIPABLE_WEAPON:
2825 if(sd->state.lr_flag != 2)
2826 sd->bonus.unstripable_equip |= EQP_WEAPON;
2827 break;
2828 case SP_UNSTRIPABLE:
2829 case SP_UNSTRIPABLE_ARMOR:
2830 if(sd->state.lr_flag != 2)
2831 sd->bonus.unstripable_equip |= EQP_ARMOR;
2832 break;
2833 case SP_UNSTRIPABLE_HELM:
2834 if(sd->state.lr_flag != 2)
2835 sd->bonus.unstripable_equip |= EQP_HELM;
2836 break;
2837 case SP_UNSTRIPABLE_SHIELD:
2838 if(sd->state.lr_flag != 2)
2839 sd->bonus.unstripable_equip |= EQP_SHIELD;
2840 break;
2841 case SP_HP_DRAIN_VALUE:
2842 if (sd->state.lr_flag == 0) {
2843 // Decomposed RC_ALL:
2844 sd->right_weapon.hp_drain[RC_NONBOSS].value += val;
2845 sd->right_weapon.hp_drain[RC_BOSS].value += val;
2846 } else if (sd->state.lr_flag == 1) {
2847 // Decomposed RC_ALL:
2848 sd->left_weapon.hp_drain[RC_NONBOSS].value += val;
2849 sd->left_weapon.hp_drain[RC_BOSS].value += val;
2850 }
2851 break;
2852 case SP_SP_DRAIN_VALUE:
2853 if (sd->state.lr_flag == 0) {
2854 // Decomposed RC_ALL:
2855 sd->right_weapon.sp_drain[RC_NONBOSS].value += val;
2856 sd->right_weapon.sp_drain[RC_BOSS].value += val;
2857 } else if (sd->state.lr_flag == 1) {
2858 // Decomposed RC_ALL:
2859 sd->left_weapon.sp_drain[RC_NONBOSS].value += val;
2860 sd->left_weapon.sp_drain[RC_BOSS].value += val;
2861 }
2862 break;
2863 case SP_SP_GAIN_VALUE:
2864 if(!sd->state.lr_flag)
2865 sd->bonus.sp_gain_value += val;
2866 break;
2867 case SP_HP_GAIN_VALUE:
2868 if(!sd->state.lr_flag)
2869 sd->bonus.hp_gain_value += val;
2870 break;
2871 case SP_MAGIC_SP_GAIN_VALUE:
2872 if(!sd->state.lr_flag)
2873 sd->bonus.magic_sp_gain_value += val;
2874 break;
2875 case SP_MAGIC_HP_GAIN_VALUE:
2876 if(!sd->state.lr_flag)
2877 sd->bonus.magic_hp_gain_value += val;
2878 break;
2879 case SP_ADD_HEAL_RATE:
2880 if(sd->state.lr_flag != 2)
2881 sd->bonus.add_heal_rate += val;
2882 break;
2883 case SP_ADD_HEAL2_RATE:
2884 if(sd->state.lr_flag != 2)
2885 sd->bonus.add_heal2_rate += val;
2886 break;
2887 case SP_ADD_ITEM_HEAL_RATE:
2888 if(sd->state.lr_flag != 2)
2889 sd->bonus.itemhealrate2 += val;
2890 break;
2891 case SP_EMATK:
2892 if(sd->state.lr_flag != 2)
2893 sd->bonus.ematk += val;
2894 break;
2895 case SP_FIXCASTRATE:
2896 if(sd->state.lr_flag != 2)
2897 sd->bonus.fixcastrate -= val;
2898 break;
2899 case SP_ADD_FIXEDCAST:
2900 if(sd->state.lr_flag != 2)
2901 sd->bonus.add_fixcast += val;
2902
2903 break;
2904 #ifdef RENEWAL_CAST
2905 case SP_VARCASTRATE:
2906 if(sd->state.lr_flag != 2)
2907 sd->bonus.varcastrate -= val;
2908 break;
2909 case SP_ADD_VARIABLECAST:
2910 if(sd->state.lr_flag != 2)
2911 sd->bonus.add_varcast += val;
2912 break;
2913 #endif
2914 case SP_ADD_MONSTER_DROP_CHAINITEM:
2915 if (sd->state.lr_flag != 2)
2916 pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, map->race_id2mask(RC_ALL), 10000);
2917 break;
2918 case SP_ADDMAXWEIGHT:
2919 if (sd->state.lr_flag != 2)
2920 sd->max_weight += val;
2921 break;
2922 default:
2923 ShowWarning("pc_bonus: unknown type %d %d !\n",type,val);
2924 Assert_report(0);
2925 break;
2926 }
2927 return 0;
2928}
2929
2930/*==========================================
2931 * Player bonus (type) with args type2 and val, called trough bonus2 (npc)
2932 *------------------------------------------*/
2933int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
2934{
2935 int i;
2936
2937 nullpo_ret(sd);
2938
2939 switch(type){
2940 case SP_ADDELE:
2941 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
2942 ShowError("pc_bonus2: SP_ADDELE: Invalid element %d\n", type2);
2943 break;
2944 }
2945 if ( type2 == ELE_ALL ) {
2946 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
2947 if ( !sd->state.lr_flag )
2948 sd->right_weapon.addele[i] += val;
2949 else if ( sd->state.lr_flag == 1 )
2950 sd->left_weapon.addele[i] += val;
2951 else if ( sd->state.lr_flag == 2 )
2952 sd->arrow_addele[i] += val;
2953 }
2954 } else {
2955 if(!sd->state.lr_flag)
2956 sd->right_weapon.addele[type2] += val;
2957 else if(sd->state.lr_flag == 1)
2958 sd->left_weapon.addele[type2] += val;
2959 else if(sd->state.lr_flag == 2)
2960 sd->arrow_addele[type2] += val;
2961 }
2962 break;
2963 case SP_ADDRACE:
2964 {
2965 uint32 race_mask = map->race_id2mask(type2);
2966 if (race_mask == RCMASK_NONE) {
2967 ShowWarning("pc_bonus2: SP_ADDRACE: Invalid Race (%d)\n", type2);
2968 break;
2969 }
2970 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
2971 if (sd->state.lr_flag == 0) {
2972 sd->right_weapon.addrace[i] += val;
2973 } else if (sd->state.lr_flag == 1) {
2974 sd->left_weapon.addrace[i] += val;
2975 } else if (sd->state.lr_flag == 2) {
2976 sd->arrow_addrace[i] += val;
2977 }
2978 }
2979 }
2980 break;
2981 case SP_ADDSIZE:
2982 if(!sd->state.lr_flag)
2983 sd->right_weapon.addsize[type2]+=val;
2984 else if(sd->state.lr_flag == 1)
2985 sd->left_weapon.addsize[type2]+=val;
2986 else if(sd->state.lr_flag == 2)
2987 sd->arrow_addsize[type2]+=val;
2988 break;
2989 case SP_SUBELE:
2990 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
2991 ShowError("pc_bonus2: SP_SUBELE: Invalid element %d\n", type2);
2992 break;
2993 }
2994 if(sd->state.lr_flag != 2) {
2995 if ( type2 == ELE_ALL ) {
2996 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ){
2997 sd->subele[i] += val;
2998 }
2999 } else {
3000 sd->subele[type2] += val;
3001 }
3002 }
3003 break;
3004 case SP_SUBRACE:
3005 {
3006 uint32 race_mask = map->race_id2mask(type2);
3007 if (race_mask == RCMASK_NONE) {
3008 ShowWarning("pc_bonus2: SP_SUBRACE: Invalid Race (%d)\n", type2);
3009 break;
3010 }
3011 if (sd->state.lr_flag == 2)
3012 break;
3013 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3014 sd->subrace[i] += val;
3015 }
3016 }
3017 break;
3018 case SP_ADDEFF:
3019 if (type2 > SC_MAX) {
3020 ShowWarning("pc_bonus2 (Add Effect): %d is not supported.\n", type2);
3021 break;
3022 }
3023 pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2,
3024 sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, 0, 0);
3025 break;
3026 case SP_ADDEFF2:
3027 if (type2 > SC_MAX) {
3028 ShowWarning("pc_bonus2 (Add Effect2): %d is not supported.\n", type2);
3029 break;
3030 }
3031 pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2,
3032 sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, ATF_SELF, 0);
3033 break;
3034 case SP_RESEFF:
3035 if (type2 < SC_COMMON_MIN || type2 > SC_COMMON_MAX) {
3036 ShowWarning("pc_bonus2 (Resist Effect): %d is not supported.\n", type2);
3037 break;
3038 }
3039 if(sd->state.lr_flag == 2)
3040 break;
3041 i = sd->reseff[type2-SC_COMMON_MIN]+val;
3042 sd->reseff[type2-SC_COMMON_MIN]= cap_value(i, 0, 10000);
3043 break;
3044 case SP_MAGIC_ADDELE:
3045 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
3046 ShowError("pc_bonus2: SP_MAGIC_ADDELE: Invalid element %d\n", type2);
3047 break;
3048 }
3049 if ( sd->state.lr_flag != 2 ) {
3050 if ( type2 == ELE_ALL ) {
3051 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ )
3052 sd->magic_addele[i] += val;
3053 } else {
3054 sd->magic_addele[type2] += val;
3055 }
3056 }
3057 break;
3058 case SP_MAGIC_ADDRACE:
3059 {
3060 uint32 race_mask = map->race_id2mask(type2);
3061 if (race_mask == RCMASK_NONE) {
3062 ShowWarning("pc_bonus2: SP_MAGIC_ADDRACE: Invalid Race (%d)\n", type2);
3063 break;
3064 }
3065 if (sd->state.lr_flag == 2)
3066 break;
3067 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3068 sd->magic_addrace[i] += val;
3069 }
3070 }
3071 break;
3072 case SP_MAGIC_ADDSIZE:
3073 if(sd->state.lr_flag != 2)
3074 sd->magic_addsize[type2]+=val;
3075 break;
3076 case SP_MAGIC_ATK_ELE:
3077 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
3078 ShowError("pc_bonus2: SP_MAGIC_ATK_ELE: Invalid element %d\n", type2);
3079 break;
3080 }
3081 if ( sd->state.lr_flag != 2 ) {
3082 if ( type2 == ELE_ALL ) {
3083 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ )
3084 sd->magic_atk_ele[i] += val;
3085 } else {
3086 sd->magic_atk_ele[type2] += val;
3087 }
3088 }
3089 break;
3090 case SP_ADD_DAMAGE_CLASS:
3091 switch (sd->state.lr_flag) {
3092 case 0: //Right hand
3093 ARR_FIND(0, ARRAYLENGTH(sd->right_weapon.add_dmg), i, sd->right_weapon.add_dmg[i].rate == 0 || sd->right_weapon.add_dmg[i].class_ == type2);
3094 if (i == ARRAYLENGTH(sd->right_weapon.add_dmg)) {
3095 ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n",
3096 ARRAYLENGTH(sd->right_weapon.add_dmg));
3097 break;
3098 }
3099 sd->right_weapon.add_dmg[i].class_ = type2;
3100 sd->right_weapon.add_dmg[i].rate += val;
3101 if (!sd->right_weapon.add_dmg[i].rate) { //Shift the rest of elements up.
3102 if( i != ARRAYLENGTH(sd->right_weapon.add_dmg) - 1 )
3103 memmove(&sd->right_weapon.add_dmg[i], &sd->right_weapon.add_dmg[i+1], sizeof(sd->right_weapon.add_dmg) - (i+1)*sizeof(sd->right_weapon.add_dmg[0]));
3104 }
3105 break;
3106 case 1: //Left hand
3107 ARR_FIND(0, ARRAYLENGTH(sd->left_weapon.add_dmg), i, sd->left_weapon.add_dmg[i].rate == 0 || sd->left_weapon.add_dmg[i].class_ == type2);
3108 if (i == ARRAYLENGTH(sd->left_weapon.add_dmg)) {
3109 ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n",
3110 ARRAYLENGTH(sd->left_weapon.add_dmg));
3111 break;
3112 }
3113 sd->left_weapon.add_dmg[i].class_ = type2;
3114 sd->left_weapon.add_dmg[i].rate += val;
3115 if (!sd->left_weapon.add_dmg[i].rate) { //Shift the rest of elements up.
3116 if( i != ARRAYLENGTH(sd->left_weapon.add_dmg) - 1 )
3117 memmove(&sd->left_weapon.add_dmg[i], &sd->left_weapon.add_dmg[i+1], sizeof(sd->left_weapon.add_dmg) - (i+1)*sizeof(sd->left_weapon.add_dmg[0]));
3118 }
3119 break;
3120 }
3121 break;
3122 case SP_ADD_MAGIC_DAMAGE_CLASS:
3123 if(sd->state.lr_flag == 2)
3124 break;
3125 ARR_FIND(0, ARRAYLENGTH(sd->add_mdmg), i, sd->add_mdmg[i].rate == 0 || sd->add_mdmg[i].class_ == type2);
3126 if (i == ARRAYLENGTH(sd->add_mdmg)) {
3127 ShowWarning("pc_bonus2: Reached max (%d) number of add Class magic dmg bonuses per character!\n", ARRAYLENGTH(sd->add_mdmg));
3128 break;
3129 }
3130 sd->add_mdmg[i].class_ = type2;
3131 sd->add_mdmg[i].rate += val;
3132 if (!sd->add_mdmg[i].rate && i != ARRAYLENGTH(sd->add_mdmg) - 1) //Shift the rest of elements up.
3133 memmove(&sd->add_mdmg[i], &sd->add_mdmg[i+1], sizeof(sd->add_mdmg) - (i+1)*sizeof(sd->add_mdmg[0]));
3134 break;
3135 case SP_ADD_DEF_CLASS:
3136 if(sd->state.lr_flag == 2)
3137 break;
3138 ARR_FIND(0, ARRAYLENGTH(sd->add_def), i, sd->add_def[i].rate == 0 || sd->add_def[i].class_ == type2);
3139 if (i == ARRAYLENGTH(sd->add_def)) {
3140 ShowWarning("pc_bonus2: Reached max (%d) number of add Class def bonuses per character!\n", ARRAYLENGTH(sd->add_def));
3141 break;
3142 }
3143 sd->add_def[i].class_ = type2;
3144 sd->add_def[i].rate += val;
3145 if ( !sd->add_def[i].rate && i != ARRAYLENGTH(sd->add_def) - 1) //Shift the rest of elements up.
3146 memmove(&sd->add_def[i], &sd->add_def[i+1], sizeof(sd->add_def) - (i+1)*sizeof(sd->add_def[0]));
3147 break;
3148 case SP_ADD_MDEF_CLASS:
3149 if(sd->state.lr_flag == 2)
3150 break;
3151 ARR_FIND(0, ARRAYLENGTH(sd->add_mdef), i, sd->add_mdef[i].rate == 0 || sd->add_mdef[i].class_ == type2);
3152 if (i == ARRAYLENGTH(sd->add_mdef)) {
3153 ShowWarning("pc_bonus2: Reached max (%d) number of add Class mdef bonuses per character!\n", ARRAYLENGTH(sd->add_mdef));
3154 break;
3155 }
3156 sd->add_mdef[i].class_ = type2;
3157 sd->add_mdef[i].rate += val;
3158 if (!sd->add_mdef[i].rate && i != ARRAYLENGTH(sd->add_mdef) - 1) //Shift the rest of elements up.
3159 memmove(&sd->add_mdef[i], &sd->add_mdef[i+1], sizeof(sd->add_mdef) - (i+1)*sizeof(sd->add_mdef[0]));
3160 break;
3161 case SP_HP_DRAIN_RATE:
3162 if (sd->state.lr_flag == 0) {
3163 // Decomposed RC_ALL:
3164 sd->right_weapon.hp_drain[RC_NONBOSS].rate += type2;
3165 sd->right_weapon.hp_drain[RC_NONBOSS].per += val;
3166 sd->right_weapon.hp_drain[RC_BOSS].rate += type2;
3167 sd->right_weapon.hp_drain[RC_BOSS].per += val;
3168 } else if (sd->state.lr_flag == 1) {
3169 // Decomposed RC_ALL:
3170 sd->left_weapon.hp_drain[RC_NONBOSS].rate += type2;
3171 sd->left_weapon.hp_drain[RC_NONBOSS].per += val;
3172 sd->left_weapon.hp_drain[RC_BOSS].rate += type2;
3173 sd->left_weapon.hp_drain[RC_BOSS].per += val;
3174 }
3175 break;
3176 case SP_HP_DRAIN_VALUE:
3177 if (sd->state.lr_flag == 0) {
3178 // Decomposed RC_ALL:
3179 sd->right_weapon.hp_drain[RC_NONBOSS].value += type2;
3180 sd->right_weapon.hp_drain[RC_NONBOSS].type = val;
3181 sd->right_weapon.hp_drain[RC_BOSS].value += type2;
3182 sd->right_weapon.hp_drain[RC_BOSS].type = val;
3183 } else if (sd->state.lr_flag == 1) {
3184 // Decomposed RC_ALL:
3185 sd->left_weapon.hp_drain[RC_NONBOSS].value += type2;
3186 sd->left_weapon.hp_drain[RC_NONBOSS].type = val;
3187 sd->left_weapon.hp_drain[RC_BOSS].value += type2;
3188 sd->left_weapon.hp_drain[RC_BOSS].type = val;
3189 }
3190 break;
3191 case SP_SP_DRAIN_RATE:
3192 if (sd->state.lr_flag == 0) {
3193 // Decomposed RC_ALL:
3194 sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2;
3195 sd->right_weapon.sp_drain[RC_NONBOSS].per += val;
3196 sd->right_weapon.sp_drain[RC_BOSS].rate += type2;
3197 sd->right_weapon.sp_drain[RC_BOSS].per += val;
3198 } else if (sd->state.lr_flag == 1) {
3199 // Decomposed RC_ALL:
3200 sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2;
3201 sd->left_weapon.sp_drain[RC_NONBOSS].per += val;
3202 sd->left_weapon.sp_drain[RC_BOSS].rate += type2;
3203 sd->left_weapon.sp_drain[RC_BOSS].per += val;
3204 }
3205 break;
3206 case SP_SP_DRAIN_VALUE:
3207 if (sd->state.lr_flag == 0) {
3208 // Decomposed RC_ALL:
3209 sd->right_weapon.sp_drain[RC_NONBOSS].value += type2;
3210 sd->right_weapon.sp_drain[RC_NONBOSS].type = val;
3211 sd->right_weapon.sp_drain[RC_BOSS].value += type2;
3212 sd->right_weapon.sp_drain[RC_BOSS].type = val;
3213 } else if (sd->state.lr_flag == 1) {
3214 // Decomposed RC_ALL:
3215 sd->left_weapon.sp_drain[RC_NONBOSS].value += type2;
3216 sd->left_weapon.sp_drain[RC_NONBOSS].type = val;
3217 sd->left_weapon.sp_drain[RC_BOSS].value += type2;
3218 sd->left_weapon.sp_drain[RC_BOSS].type = val;
3219 }
3220 break;
3221 case SP_HP_VANISH_RATE:
3222 if (sd->state.lr_flag != 2) {
3223 sd->bonus.hp_vanish_rate += type2;
3224 sd->bonus.hp_vanish_per = max(sd->bonus.hp_vanish_per, val);
3225 sd->bonus.hp_vanish_trigger = 0;
3226 }
3227 break;
3228 case SP_SP_VANISH_RATE:
3229 if (sd->state.lr_flag != 2) {
3230 sd->bonus.sp_vanish_rate += type2;
3231 sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per, val);
3232 sd->bonus.sp_vanish_trigger = 0;
3233 }
3234 break;
3235 case SP_GET_ZENY_NUM:
3236 if(sd->state.lr_flag != 2 && sd->bonus.get_zeny_rate < val) {
3237 sd->bonus.get_zeny_rate = val;
3238 sd->bonus.get_zeny_num = type2;
3239 }
3240 break;
3241 case SP_ADD_GET_ZENY_NUM:
3242 if(sd->state.lr_flag != 2) {
3243 sd->bonus.get_zeny_rate += val;
3244 sd->bonus.get_zeny_num += type2;
3245 }
3246 break;
3247 case SP_WEAPON_COMA_ELE:
3248 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
3249 ShowError("pc_bonus2: SP_WEAPON_COMA_ELE: Invalid element %d\n", type2);
3250 break;
3251 }
3252 if(sd->state.lr_flag == 2)
3253 break;
3254 if ( type2 == ELE_ALL ) {
3255 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ )
3256 sd->weapon_coma_ele[i] += val;
3257 } else {
3258 sd->weapon_coma_ele[type2] += val;
3259 }
3260 sd->special_state.bonus_coma = 1;
3261 break;
3262 case SP_WEAPON_COMA_RACE:
3263 {
3264 uint32 race_mask = map->race_id2mask(type2);
3265 if (race_mask == RCMASK_NONE) {
3266 ShowWarning("pc_bonus2: SP_WEAPON_COMA_RACE: Invalid Race (%d)\n", type2);
3267 break;
3268 }
3269 if(sd->state.lr_flag == 2)
3270 break;
3271 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3272 sd->weapon_coma_race[i] += val;
3273 }
3274 sd->special_state.bonus_coma = 1;
3275 }
3276 break;
3277 case SP_WEAPON_ATK:
3278 if(sd->state.lr_flag != 2)
3279 sd->weapon_atk[type2]+=val;
3280 break;
3281 case SP_WEAPON_ATK_RATE:
3282 if(sd->state.lr_flag != 2)
3283 sd->weapon_atk_rate[type2]+=val;
3284 break;
3285 case SP_CRITICAL_ADDRACE:
3286 {
3287 uint32 race_mask = map->race_id2mask(type2);
3288 if (race_mask == RCMASK_NONE) {
3289 ShowWarning("pc_bonus2: SP_CRITICAL_ADDRACE: Invalid Race (%d)\n", type2);
3290 break;
3291 }
3292 if (sd->state.lr_flag == 2)
3293 break;
3294 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3295 sd->critaddrace[i] += val*10;
3296 }
3297 }
3298 break;
3299 case SP_ADDEFF_WHENHIT:
3300 if (type2 > SC_MAX) {
3301 ShowWarning("pc_bonus2 (Add Effect when hit): %d is not supported.\n", type2);
3302 break;
3303 }
3304 if(sd->state.lr_flag != 2)
3305 pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, val, 0, 0, 0);
3306 break;
3307 case SP_SKILL_ATK:
3308 if(sd->state.lr_flag == 2)
3309 break;
3310 ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == 0 || sd->skillatk[i].id == type2);
3311 if (i == ARRAYLENGTH(sd->skillatk)) {
3312 //Better mention this so the array length can be updated. [Skotlex]
3313 ShowDebug("script->run: bonus2 bSkillAtk reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3314 ARRAYLENGTH(sd->skillatk), type2, val);
3315 break;
3316 }
3317 if (sd->skillatk[i].id == type2)
3318 sd->skillatk[i].val += val;
3319 else {
3320 sd->skillatk[i].id = type2;
3321 sd->skillatk[i].val = val;
3322 }
3323 break;
3324 case SP_SKILL_HEAL:
3325 if(sd->state.lr_flag == 2)
3326 break;
3327 ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == 0 || sd->skillheal[i].id == type2);
3328 if (i == ARRAYLENGTH(sd->skillheal)) {
3329 // Better mention this so the array length can be updated. [Skotlex]
3330 ShowDebug("script->run: bonus2 bSkillHeal reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3331 ARRAYLENGTH(sd->skillheal), type2, val);
3332 break;
3333 }
3334 if (sd->skillheal[i].id == type2)
3335 sd->skillheal[i].val += val;
3336 else {
3337 sd->skillheal[i].id = type2;
3338 sd->skillheal[i].val = val;
3339 }
3340 break;
3341 case SP_SKILL_HEAL2:
3342 if(sd->state.lr_flag == 2)
3343 break;
3344 ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == 0 || sd->skillheal2[i].id == type2);
3345 if (i == ARRAYLENGTH(sd->skillheal2)) {
3346 // Better mention this so the array length can be updated. [Skotlex]
3347 ShowDebug("script->run: bonus2 bSkillHeal2 reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3348 ARRAYLENGTH(sd->skillheal2), type2, val);
3349 break;
3350 }
3351 if (sd->skillheal2[i].id == type2)
3352 sd->skillheal2[i].val += val;
3353 else {
3354 sd->skillheal2[i].id = type2;
3355 sd->skillheal2[i].val = val;
3356 }
3357 break;
3358 case SP_ADD_SKILL_BLOW:
3359 if(sd->state.lr_flag == 2)
3360 break;
3361 ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2);
3362 if (i == ARRAYLENGTH(sd->skillblown)) {
3363 //Better mention this so the array length can be updated. [Skotlex]
3364 ShowDebug("script->run: bonus2 bSkillBlown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3365 ARRAYLENGTH(sd->skillblown), type2, val);
3366 break;
3367 }
3368 if(sd->skillblown[i].id == type2)
3369 sd->skillblown[i].val += val;
3370 else {
3371 sd->skillblown[i].id = type2;
3372 sd->skillblown[i].val = val;
3373 }
3374 break;
3375#ifndef RENEWAL_CAST
3376 case SP_VARCASTRATE:
3377#endif
3378 case SP_CASTRATE:
3379 if(sd->state.lr_flag == 2)
3380 break;
3381 ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2);
3382 if (i == ARRAYLENGTH(sd->skillcast)) {
3383 //Better mention this so the array length can be updated. [Skotlex]
3384 ShowDebug("script->run: bonus2 %s reached its limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3385 type == SP_CASTRATE ? "bCastRate" : "bVariableCastrate",
3386 ARRAYLENGTH(sd->skillcast), type2, val);
3387 break;
3388 }
3389 if(sd->skillcast[i].id == type2)
3390 sd->skillcast[i].val += val;
3391 else {
3392 sd->skillcast[i].id = type2;
3393 sd->skillcast[i].val = val;
3394 }
3395 break;
3396
3397 case SP_FIXCASTRATE:
3398 if(sd->state.lr_flag == 2)
3399 break;
3400
3401 ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2);
3402
3403 if (i == ARRAYLENGTH(sd->skillfixcastrate)) {
3404 ShowDebug("script->run: bonus2 bFixedCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3405 ARRAYLENGTH(sd->skillfixcastrate), type2, val);
3406 break;
3407 }
3408
3409 if(sd->skillfixcastrate[i].id == type2)
3410 sd->skillfixcastrate[i].val -= val;
3411
3412 else {
3413 sd->skillfixcastrate[i].id = type2;
3414 sd->skillfixcastrate[i].val -= val;
3415 }
3416
3417 break;
3418
3419 case SP_HP_LOSS_RATE:
3420 if(sd->state.lr_flag != 2) {
3421 sd->hp_loss.value = type2;
3422 sd->hp_loss.rate = val;
3423 }
3424 break;
3425 case SP_HP_REGEN_RATE:
3426 if(sd->state.lr_flag != 2) {
3427 sd->hp_regen.value = type2;
3428 sd->hp_regen.rate = val;
3429 }
3430 break;
3431 case SP_ADDRACE2:
3432 if (!(type2 > RC2_NONE && type2 < RC2_MAX))
3433 break;
3434 if(sd->state.lr_flag != 2)
3435 sd->right_weapon.addrace2[type2] += val;
3436 else
3437 sd->left_weapon.addrace2[type2] += val;
3438 break;
3439 case SP_SUBSIZE:
3440 if(sd->state.lr_flag != 2)
3441 sd->subsize[type2]+=val;
3442 break;
3443 case SP_SUBRACE2:
3444 if (!(type2 > RC2_NONE && type2 < RC2_MAX))
3445 break;
3446 if(sd->state.lr_flag != 2)
3447 sd->subrace2[type2]+=val;
3448 break;
3449 case SP_ADD_ITEM_HEAL_RATE:
3450 if(sd->state.lr_flag == 2)
3451 break;
3452 //Standard item bonus.
3453 for(i=0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid && sd->itemhealrate[i].nameid != type2; i++);
3454 if (i == ARRAYLENGTH(sd->itemhealrate)) {
3455 ShowWarning("pc_bonus2: Reached max (%d) number of item heal bonuses per character!\n", ARRAYLENGTH(sd->itemhealrate));
3456 break;
3457 }
3458 sd->itemhealrate[i].nameid = type2;
3459 sd->itemhealrate[i].rate += val;
3460 break;
3461 case SP_EXP_ADDRACE:
3462 {
3463 uint32 race_mask = map->race_id2mask(type2);
3464 if (race_mask == RCMASK_NONE) {
3465 ShowWarning("pc_bonus2: SP_EXP_ADDRACE: Invalid Race (%d)\n", type2);
3466 break;
3467 }
3468 if (sd->state.lr_flag == 2)
3469 break;
3470 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3471 sd->expaddrace[i] += val;
3472 }
3473 }
3474 break;
3475 case SP_SP_GAIN_RACE:
3476 {
3477 uint32 race_mask = map->race_id2mask(type2);
3478 if (race_mask == RCMASK_NONE) {
3479 ShowWarning("pc_bonus2: SP_SP_GAIN_RACE: Invalid Race (%d)\n", type2);
3480 break;
3481 }
3482 if (sd->state.lr_flag == 2)
3483 break;
3484 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3485 sd->sp_gain_race[i] += val;
3486 }
3487 }
3488 break;
3489 case SP_ADD_MONSTER_DROP_ITEM:
3490 if (sd->state.lr_flag != 2)
3491 pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, map->race_id2mask(RC_ALL), val);
3492 break;
3493 case SP_SP_LOSS_RATE:
3494 if(sd->state.lr_flag != 2) {
3495 sd->sp_loss.value = type2;
3496 sd->sp_loss.rate = val;
3497 }
3498 break;
3499 case SP_SP_REGEN_RATE:
3500 if(sd->state.lr_flag != 2) {
3501 sd->sp_regen.value = type2;
3502 sd->sp_regen.rate = val;
3503 }
3504 break;
3505 case SP_HP_DRAIN_VALUE_RACE:
3506 {
3507 uint32 race_mask = map->race_id2mask(type2);
3508 if (race_mask == RCMASK_NONE) {
3509 ShowWarning("pc_bonus2: SP_HP_DRAIN_VALUE_RACE: Invalid Race (%d)\n", type2);
3510 break;
3511 }
3512 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3513 if (sd->state.lr_flag == 0)
3514 sd->right_weapon.hp_drain[i].value += val;
3515 else if(sd->state.lr_flag == 1)
3516 sd->left_weapon.hp_drain[i].value += val;
3517 }
3518 }
3519 break;
3520 case SP_SP_DRAIN_VALUE_RACE:
3521 {
3522 uint32 race_mask = map->race_id2mask(type2);
3523 if (race_mask == RCMASK_NONE) {
3524 ShowWarning("pc_bonus2: SP_SP_DRAIN_VALUE_RACE: Invalid Race (%d)\n", type2);
3525 break;
3526 }
3527 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3528 if (sd->state.lr_flag == 0)
3529 sd->right_weapon.sp_drain[i].value += val;
3530 else if (sd->state.lr_flag == 1)
3531 sd->left_weapon.sp_drain[i].value += val;
3532 }
3533 }
3534 break;
3535 case SP_IGNORE_MDEF_RATE:
3536 {
3537 uint32 race_mask = map->race_id2mask(type2);
3538 if (race_mask == RCMASK_NONE) {
3539 ShowWarning("pc_bonus2: SP_IGNORE_MDEF_RATE: Invalid Race (%d)\n", type2);
3540 break;
3541 }
3542 if (sd->state.lr_flag == 2)
3543 break;
3544 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3545 sd->ignore_mdef[i] += val;
3546 }
3547 }
3548 break;
3549 case SP_IGNORE_DEF_RATE:
3550 {
3551 uint32 race_mask = map->race_id2mask(type2);
3552 if (race_mask == RCMASK_NONE) {
3553 ShowWarning("pc_bonus2: SP_IGNORE_DEF_RATE: Invalid Race (%d)\n", type2);
3554 break;
3555 }
3556 if (sd->state.lr_flag == 2)
3557 break;
3558 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3559 sd->ignore_def[i] += val;
3560 }
3561 }
3562 break;
3563 case SP_SP_GAIN_RACE_ATTACK:
3564 {
3565 uint32 race_mask = map->race_id2mask(type2);
3566 if (race_mask == RCMASK_NONE) {
3567 ShowWarning("pc_bonus2: SP_SP_GAIN_RACE_ATTACK: Invalid Race (%d)\n", type2);
3568 break;
3569 }
3570 if (sd->state.lr_flag == 2)
3571 break;
3572 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3573 sd->sp_gain_race_attack[i] = cap_value(sd->sp_gain_race_attack[i] + val, 0, INT16_MAX);
3574 }
3575 }
3576 break;
3577 case SP_HP_GAIN_RACE_ATTACK:
3578 {
3579 uint32 race_mask = map->race_id2mask(type2);
3580 if (race_mask == RCMASK_NONE) {
3581 ShowWarning("pc_bonus2: SP_HP_GAIN_RACE_ATTACK: Invalid Race (%d)\n", type2);
3582 break;
3583 }
3584 if (sd->state.lr_flag == 2)
3585 break;
3586 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3587 sd->hp_gain_race_attack[i] = cap_value(sd->hp_gain_race_attack[i] + val, 0, INT16_MAX);
3588 }
3589 }
3590 break;
3591 case SP_SKILL_USE_SP_RATE: //bonus2 bSkillUseSPrate,n,x;
3592 if(sd->state.lr_flag == 2)
3593 break;
3594 ARR_FIND(0, ARRAYLENGTH(sd->skillusesprate), i, sd->skillusesprate[i].id == 0 || sd->skillusesprate[i].id == type2);
3595 if (i == ARRAYLENGTH(sd->skillusesprate)) {
3596 ShowDebug("script->run: bonus2 bSkillUseSPrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3597 ARRAYLENGTH(sd->skillusesprate), type2, val);
3598 break;
3599 }
3600 if (sd->skillusesprate[i].id == type2)
3601 sd->skillusesprate[i].val += val;
3602 else {
3603 sd->skillusesprate[i].id = type2;
3604 sd->skillusesprate[i].val = val;
3605 }
3606 break;
3607 case SP_SKILL_COOLDOWN:
3608 if(sd->state.lr_flag == 2)
3609 break;
3610 ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2);
3611 if (i == ARRAYLENGTH(sd->skillcooldown)) {
3612 ShowDebug("script->run: bonus2 bSkillCoolDown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3613 ARRAYLENGTH(sd->skillcooldown), type2, val);
3614 break;
3615 }
3616 if (sd->skillcooldown[i].id == type2)
3617 sd->skillcooldown[i].val += val;
3618 else {
3619 sd->skillcooldown[i].id = type2;
3620 sd->skillcooldown[i].val = val;
3621 }
3622 break;
3623 case SP_SKILL_FIXEDCAST:
3624 if(sd->state.lr_flag == 2)
3625 break;
3626 ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2);
3627 if (i == ARRAYLENGTH(sd->skillfixcast)) {
3628 ShowDebug("script->run: bonus2 bSkillFixedCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3629 ARRAYLENGTH(sd->skillfixcast), type2, val);
3630 break;
3631 }
3632 if (sd->skillfixcast[i].id == type2)
3633 sd->skillfixcast[i].val += val;
3634 else {
3635 sd->skillfixcast[i].id = type2;
3636 sd->skillfixcast[i].val = val;
3637 }
3638 break;
3639 case SP_SKILL_VARIABLECAST:
3640 if(sd->state.lr_flag == 2)
3641 break;
3642 ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2);
3643 if (i == ARRAYLENGTH(sd->skillvarcast)) {
3644 ShowDebug("script->run: bonus2 bSkillVariableCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3645 ARRAYLENGTH(sd->skillvarcast), type2, val);
3646 break;
3647 }
3648 if (sd->skillvarcast[i].id == type2)
3649 sd->skillvarcast[i].val += val;
3650 else {
3651 sd->skillvarcast[i].id = type2;
3652 sd->skillvarcast[i].val = val;
3653 }
3654 break;
3655 #ifdef RENEWAL_CAST
3656 case SP_VARCASTRATE:
3657 if(sd->state.lr_flag == 2)
3658 break;
3659 ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2);
3660 if (i == ARRAYLENGTH(sd->skillcast)) {
3661 ShowDebug("script->run: bonus2 bVariableCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3662 ARRAYLENGTH(sd->skillcast), type2, val);
3663 break;
3664 }
3665 if(sd->skillcast[i].id == type2)
3666 sd->skillcast[i].val -= val;
3667 else {
3668 sd->skillcast[i].id = type2;
3669 sd->skillcast[i].val -= val;
3670 }
3671 break;
3672 #endif
3673 case SP_SKILL_USE_SP: //bonus2 bSkillUseSP,n,x;
3674 if(sd->state.lr_flag == 2)
3675 break;
3676 ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2);
3677 if (i == ARRAYLENGTH(sd->skillusesp)) {
3678 ShowDebug("script->run: bonus2 bSkillUseSP reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",
3679 ARRAYLENGTH(sd->skillusesp), type2, val);
3680 break;
3681 }
3682 if (sd->skillusesp[i].id == type2)
3683 sd->skillusesp[i].val += val;
3684 else {
3685 sd->skillusesp[i].id = type2;
3686 sd->skillusesp[i].val = val;
3687 }
3688 break;
3689 case SP_ADD_MONSTER_DROP_CHAINITEM:
3690 {
3691 uint32 race_mask = map->race_id2mask(val);
3692 if (race_mask == RCMASK_NONE) {
3693 ShowWarning("pc_bonus2: SP_ADD_MONSTER_DROP_CHAINITEM: Invalid Race (%d)\n", val);
3694 break;
3695 }
3696 if (sd->state.lr_flag != 2)
3697 pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, type2, race_mask, 10000);
3698 }
3699 break;
3700#ifdef RENEWAL
3701 case SP_RACE_TOLERANCE:
3702 {
3703 uint32 race_mask = map->race_id2mask(type2);
3704 if (race_mask == RCMASK_NONE) {
3705 ShowWarning("pc_bonus2: SP_RACE_TOLERANCE: Invalid Race (%d)\n", type2);
3706 break;
3707 }
3708 if (sd->state.lr_flag == 2)
3709 break;
3710 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask)
3711 sd->race_tolerance[i] += val;
3712 }
3713 break;
3714#endif
3715 default:
3716 ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val);
3717 Assert_report(0);
3718 break;
3719 }
3720 return 0;
3721}
3722
3723int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val)
3724{
3725 int i;
3726 nullpo_ret(sd);
3727
3728 switch(type){
3729 case SP_ADD_MONSTER_DROP_ITEM:
3730 {
3731 uint32 race_mask = map->race_id2mask(type3);
3732 if (race_mask == RCMASK_NONE) {
3733 ShowWarning("pc_bonus2: SP_ADD_MONSTER_DROP_ITEM: Invalid Race (%d)\n", type3);
3734 break;
3735 }
3736 if (sd->state.lr_flag != 2)
3737 pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, race_mask, val);
3738 }
3739 break;
3740 case SP_ADD_CLASS_DROP_ITEM:
3741 if(sd->state.lr_flag != 2)
3742 pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val);
3743 break;
3744 case SP_AUTOSPELL:
3745 if(sd->state.lr_flag != 2)
3746 {
3747 int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self.
3748 target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF));
3749 pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell),
3750 target?-type2:type2, type3, val, 0, status->current_equip_card_id);
3751 }
3752 break;
3753 case SP_AUTOSPELL_WHENHIT:
3754 if(sd->state.lr_flag != 2)
3755 {
3756 int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self.
3757 target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF));
3758 pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2),
3759 target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, status->current_equip_card_id);
3760 }
3761 break;
3762 case SP_SP_DRAIN_RATE:
3763 if (sd->state.lr_flag == 0) {
3764 // Decomposed RC_ALL:
3765 sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2;
3766 sd->right_weapon.sp_drain[RC_NONBOSS].per += type3;
3767 sd->right_weapon.sp_drain[RC_NONBOSS].type = val;
3768 sd->right_weapon.sp_drain[RC_BOSS].rate += type2;
3769 sd->right_weapon.sp_drain[RC_BOSS].per += type3;
3770 sd->right_weapon.sp_drain[RC_BOSS].type = val;
3771 } else if (sd->state.lr_flag == 1) {
3772 // Decomposed RC_ALL:
3773 sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2;
3774 sd->left_weapon.sp_drain[RC_NONBOSS].per += type3;
3775 sd->left_weapon.sp_drain[RC_NONBOSS].type = val;
3776 sd->left_weapon.sp_drain[RC_BOSS].rate += type2;
3777 sd->left_weapon.sp_drain[RC_BOSS].per += type3;
3778 sd->left_weapon.sp_drain[RC_BOSS].type = val;
3779 }
3780 break;
3781 case SP_HP_DRAIN_RATE_RACE:
3782 {
3783 uint32 race_mask = map->race_id2mask(type2);
3784 if (race_mask == RCMASK_NONE) {
3785 ShowWarning("pc_bonus3: SP_HP_DRAIN_RATE_RACE: Invalid Race (%d)\n", type2);
3786 break;
3787 }
3788 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3789 if (sd->state.lr_flag == 0) {
3790 sd->right_weapon.hp_drain[i].rate += type3;
3791 sd->right_weapon.hp_drain[i].per += val;
3792 } else if(sd->state.lr_flag == 1) {
3793 sd->left_weapon.hp_drain[i].rate += type3;
3794 sd->left_weapon.hp_drain[i].per += val;
3795 }
3796 }
3797 }
3798 break;
3799 case SP_SP_DRAIN_RATE_RACE:
3800 {
3801 uint32 race_mask = map->race_id2mask(type2);
3802 if (race_mask == RCMASK_NONE) {
3803 ShowWarning("pc_bonus3: SP_SP_DRAIN_RATE_RACE: Invalid Race (%d)\n", type2);
3804 break;
3805 }
3806 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3807 if (sd->state.lr_flag == 0) {
3808 sd->right_weapon.sp_drain[i].rate += type3;
3809 sd->right_weapon.sp_drain[i].per += val;
3810 } else if(sd->state.lr_flag == 1) {
3811 sd->left_weapon.sp_drain[i].rate += type3;
3812 sd->left_weapon.sp_drain[i].per += val;
3813 }
3814 }
3815 }
3816 break;
3817 case SP_ADDEFF:
3818 if (type2 > SC_MAX) {
3819 ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2);
3820 break;
3821 }
3822 pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2,
3823 sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val, 0);
3824 break;
3825
3826 case SP_ADDEFF_WHENHIT:
3827 if (type2 > SC_MAX) {
3828 ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2);
3829 break;
3830 }
3831 if(sd->state.lr_flag != 2)
3832 pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val, 0);
3833 break;
3834
3835 case SP_ADDEFF_ONSKILL:
3836 if( type3 > SC_MAX ) {
3837 ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3);
3838 break;
3839 }
3840 if( sd->state.lr_flag != 2 )
3841 pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET);
3842 break;
3843
3844 case SP_ADDELE:
3845 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
3846 ShowError("pc_bonus3: SP_ADDELE: Invalid element %d\n", type2);
3847 break;
3848 }
3849 if ( sd->state.lr_flag != 2 ) {
3850 if ( type2 == ELE_ALL ) {
3851 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ )
3852 pc_bonus_addele(sd, (unsigned char)i, type3, val);
3853 } else {
3854 pc_bonus_addele(sd, (unsigned char)type2, type3, val);
3855 }
3856 }
3857 break;
3858
3859 case SP_SUBELE:
3860 if( (type2 >= ELE_MAX && type2 != ELE_ALL) || (type2 < ELE_NEUTRAL) ) {
3861 ShowError("pc_bonus3: SP_SUBELE: Invalid element %d\n", type2);
3862 break;
3863 }
3864 if ( sd->state.lr_flag != 2 ) {
3865 if ( type2 == ELE_ALL ) {
3866 for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ )
3867 pc_bonus_subele(sd, (unsigned char)i, type3, val);
3868 } else {
3869 pc_bonus_subele(sd, (unsigned char)type2, type3, val);
3870 }
3871 }
3872 break;
3873 case SP_HP_VANISH_RATE:
3874 if (sd->state.lr_flag != 2) {
3875 sd->bonus.hp_vanish_rate += type2;
3876 sd->bonus.hp_vanish_per = max(sd->bonus.hp_vanish_per, type3);
3877 sd->bonus.hp_vanish_trigger = val;
3878 }
3879 break;
3880 case SP_SP_VANISH_RATE:
3881 if (sd->state.lr_flag != 2) {
3882 sd->bonus.sp_vanish_rate += type2;
3883 sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per, type3);
3884 sd->bonus.sp_vanish_trigger = val;
3885 }
3886 break;
3887
3888 default:
3889 ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val);
3890 Assert_report(0);
3891 break;
3892 }
3893
3894 return 0;
3895}
3896
3897int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4,int val) {
3898 int i;
3899 nullpo_ret(sd);
3900
3901 switch(type) {
3902 case SP_AUTOSPELL:
3903 if(sd->state.lr_flag != 2)
3904 pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1) ? type2 : -type2, (val&2) ? -type3 : type3, type4, 0, status->current_equip_card_id);
3905 break;
3906
3907 case SP_AUTOSPELL_WHENHIT:
3908 if(sd->state.lr_flag != 2)
3909 pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1) ? type2 : -type2, (val&2) ? -type3 : type3, type4, BF_NORMAL|BF_SKILL, status->current_equip_card_id);
3910 break;
3911
3912 case SP_AUTOSPELL_ONSKILL:
3913 if(sd->state.lr_flag != 2) {
3914 int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self.
3915 target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF));
3916
3917 pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, target?-type3:type3, type4, val, status->current_equip_card_id);
3918 }
3919 break;
3920
3921 case SP_ADDEFF_ONSKILL:
3922 if( type2 > SC_MAX ) {
3923 ShowWarning("pc_bonus4 (Add Effect on skill): %d is not supported.\n", type2);
3924 break;
3925 }
3926 if( sd->state.lr_flag != 2 )
3927 pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, type4, type2, val);
3928 break;
3929
3930 case SP_SET_DEF_RACE: //bonus4 bSetDefRace,n,x,r,y;
3931 {
3932 uint32 race_mask = map->race_id2mask(type2);
3933 if (race_mask == RCMASK_NONE) {
3934 ShowWarning("pc_bonus4: SP_SET_DEF_RACE: Invalid Race (%d)\n", type2);
3935 break;
3936 }
3937 if (sd->state.lr_flag == 2)
3938 break;
3939 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3940 sd->def_set_race[i].rate = type3;
3941 sd->def_set_race[i].tick = type4;
3942 sd->def_set_race[i].value = val;
3943 }
3944 }
3945 break;
3946
3947 case SP_SET_MDEF_RACE: //bonus4 bSetMDefRace,n,x,r,y;
3948 {
3949 uint32 race_mask = map->race_id2mask(type2);
3950 if (race_mask == RCMASK_NONE) {
3951 ShowWarning("pc_bonus4: SP_SET_MDEF_RACE: Invalid Race (%d)\n", type2);
3952 break;
3953 }
3954 if (sd->state.lr_flag == 2)
3955 break;
3956 BONUS_FOREACH_RCARRAY_FROMMASK(i, race_mask) {
3957 sd->mdef_set_race[i].rate = type3;
3958 sd->mdef_set_race[i].tick = type4;
3959 sd->mdef_set_race[i].value = val;
3960 }
3961 }
3962 break;
3963
3964 case SP_ADDEFF:
3965 {
3966 uint16 duration;
3967 if (type2 > SC_MAX) {
3968 ShowWarning("pc_bonus4 (Add Effect): %d is not supported.\n", type2);
3969 break;
3970 }
3971 if (val < 0 || val > UINT16_MAX) {
3972 ShowWarning("pc_bonus4 (Add Effect): invalid duration %d. Valid range: [0:%d].\n", val, UINT16_MAX);
3973 duration = (val < 0 ? 0 : UINT16_MAX);
3974 } else {
3975 duration = (uint16)val;
3976 }
3977
3978 pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2,
3979 sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, type4, duration);
3980 }
3981 break;
3982
3983 default:
3984 ShowWarning("pc_bonus4: unknown type %d %d %d %d %d!\n",type,type2,type3,type4,val);
3985 Assert_report(0);
3986 break;
3987 }
3988
3989 return 0;
3990}
3991
3992int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val) {
3993 nullpo_ret(sd);
3994
3995 switch(type){
3996 case SP_AUTOSPELL:
3997 if(sd->state.lr_flag != 2)
3998 pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1) ? type2 : -type2, (val&2) ? -type3 : type3, type4, type5, status->current_equip_card_id);
3999 break;
4000
4001 case SP_AUTOSPELL_WHENHIT:
4002 if(sd->state.lr_flag != 2)
4003 pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1) ? type2 : -type2, (val&2) ? -type3 : type3, type4, type5, status->current_equip_card_id);
4004 break;
4005
4006 case SP_AUTOSPELL_ONSKILL:
4007 if(sd->state.lr_flag != 2)
4008 pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, (val&1) ? -type3 : type3, (val&2) ? -type4 : type4, type5, status->current_equip_card_id);
4009 break;
4010
4011 default:
4012 ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val);
4013 Assert_report(0);
4014 break;
4015 }
4016
4017 return 0;
4018}
4019
4020#undef BONUS_FOREACH_RCARRAY_FROMMASK
4021
4022/*==========================================
4023 * Grants a player a given skill.
4024 * Flag values: @see enum pc_skill_flag
4025 *------------------------------------------*/
4026int pc_skill(struct map_session_data *sd, int id, int level, int flag)
4027{
4028 uint16 index = 0;
4029 nullpo_ret(sd);
4030
4031 if (!(index = skill->get_index(id))) {
4032 ShowError("pc_skill: Skill with id %d does not exist in the skill database\n", id);
4033 return 0;
4034 }
4035 if( level > MAX_SKILL_LEVEL ) {
4036 ShowError("pc_skill: Skill level %d too high. Max lv supported is %d\n", level, MAX_SKILL_LEVEL);
4037 return 0;
4038 }
4039 if( flag == SKILL_GRANT_TEMPSTACK && sd->status.skill[index].lv + level > MAX_SKILL_LEVEL ) {
4040 ShowError("pc_skill: Skill level bonus %d too high. Max lv supported is %d. Curr lv is %d\n", level, MAX_SKILL_LEVEL, sd->status.skill[index].lv);
4041 return 0;
4042 }
4043
4044 switch( flag ){
4045 case SKILL_GRANT_PERMANENT: //Set skill data overwriting whatever was there before.
4046 sd->status.skill[index].id = id;
4047 sd->status.skill[index].lv = level;
4048 sd->status.skill[index].flag = SKILL_FLAG_PERMANENT;
4049 if( level == 0 ) { //Remove skill.
4050 sd->status.skill[index].id = 0;
4051 clif->deleteskill(sd,id);
4052 } else
4053 clif->addskill(sd,id);
4054 if( !skill->dbs->db[index].inf ) //Only recalculate for passive skills.
4055 status_calc_pc(sd, SCO_NONE);
4056 break;
4057 case SKILL_GRANT_TEMPORARY: //Item bonus skill.
4058 if( sd->status.skill[index].id == id ) {
4059 if( sd->status.skill[index].lv >= level )
4060 return 0;
4061 if( sd->status.skill[index].flag == SKILL_FLAG_PERMANENT ) //Non-granted skill, store it's level.
4062 sd->status.skill[index].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[index].lv;
4063 } else {
4064 sd->status.skill[index].id = id;
4065 sd->status.skill[index].flag = SKILL_FLAG_TEMPORARY;
4066 }
4067 sd->status.skill[index].lv = level;
4068 break;
4069 case SKILL_GRANT_TEMPSTACK: //Add skill bonus on top of what you had.
4070 if( sd->status.skill[index].id == id ) {
4071 if( sd->status.skill[index].flag == SKILL_FLAG_PERMANENT )
4072 sd->status.skill[index].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[index].lv; // Store previous level.
4073 } else {
4074 sd->status.skill[index].id = id;
4075 sd->status.skill[index].flag = SKILL_FLAG_TEMPORARY; //Set that this is a bonus skill.
4076 }
4077 sd->status.skill[index].lv += level;
4078 break;
4079 case SKILL_GRANT_UNCONDITIONAL:
4080 sd->status.skill[index].id = id;
4081 sd->status.skill[index].lv = level;
4082 sd->status.skill[index].flag = SKILL_FLAG_PERM_GRANTED;
4083 if( level == 0 ) { //Remove skill.
4084 sd->status.skill[index].id = 0;
4085 clif->deleteskill(sd,id);
4086 } else
4087 clif->addskill(sd,id);
4088 if( !skill->dbs->db[index].inf ) //Only recalculate for passive skills.
4089 status_calc_pc(sd, SCO_NONE);
4090 break;
4091 default: //Unknown flag?
4092 return 0;
4093 }
4094 return 1;
4095}
4096
4097/**
4098 * Checks if the given card can be inserted into the given equipment piece.
4099 *
4100 * @param sd The current character.
4101 * @param idx_card The card's inventory index (note: it must be a valid index and can be checked by pc_can_insert_card)
4102 * @param idx_equip The target equipment's inventory index.
4103 * @retval true if the card can be inserted.
4104 */
4105bool pc_can_insert_card_into(struct map_session_data* sd, int idx_card, int idx_equip)
4106{
4107 int i;
4108
4109 nullpo_ret(sd);
4110
4111 if (idx_equip < 0 || idx_equip >= MAX_INVENTORY || sd->inventory_data[idx_equip] == NULL)
4112 return false; //Invalid item index.
4113 if (sd->status.inventory[idx_equip].nameid <= 0 || sd->status.inventory[idx_equip].amount < 1)
4114 return false; // target item missing
4115 if (sd->inventory_data[idx_equip]->type != IT_WEAPON && sd->inventory_data[idx_equip]->type != IT_ARMOR)
4116 return false; // only weapons and armor are allowed
4117 if (sd->status.inventory[idx_equip].identify == 0)
4118 return false; // target must be identified
4119 if (itemdb_isspecial(sd->status.inventory[idx_equip].card[0]))
4120 return false; // card slots reserved for other purposes
4121 if (sd->status.inventory[idx_equip].equip != 0)
4122 return false; // item must be unequipped
4123 if ((sd->inventory_data[idx_equip]->equip & sd->inventory_data[idx_card]->equip) == 0)
4124 return false; // card cannot be compounded on this item type
4125 if (sd->inventory_data[idx_equip]->type == IT_WEAPON && sd->inventory_data[idx_card]->equip == EQP_SHIELD)
4126 return false; // attempted to place shield card on left-hand weapon.
4127
4128 ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0);
4129 if (i == sd->inventory_data[idx_equip]->slot)
4130 return false; // no free slots
4131 return true;
4132}
4133
4134/**
4135 * Checks if the given item is card and it can be inserted into some equipment.
4136 *
4137 * @param sd The current character.
4138 * @param idx_card The card's inventory index.
4139 * @retval true if the card can be inserted.
4140 */
4141bool pc_can_insert_card(struct map_session_data* sd, int idx_card)
4142{
4143 nullpo_ret(sd);
4144
4145 if (idx_card < 0 || idx_card >= MAX_INVENTORY || sd->inventory_data[idx_card] == NULL)
4146 return false; //Invalid card index.
4147 if (sd->status.inventory[idx_card].nameid <= 0 || sd->status.inventory[idx_card].amount < 1)
4148 return false; // target card missing
4149 if (sd->inventory_data[idx_card]->type != IT_CARD)
4150 return false; // must be a card
4151 return true;
4152}
4153
4154/*==========================================
4155 * Attempt to insert card into item.
4156 * Return:
4157 * 0 = fail
4158 * 1 = success
4159 *------------------------------------------*/
4160int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip)
4161{
4162 int nameid;
4163
4164 nullpo_ret(sd);
4165
4166 if (sd->state.trading != 0)
4167 return 0;
4168
4169 if (!pc->can_insert_card(sd, idx_card) || !pc->can_insert_card_into(sd, idx_card, idx_equip))
4170 return 0;
4171
4172 // remember the card id to insert
4173 nameid = sd->status.inventory[idx_card].nameid;
4174
4175 if( pc->delitem(sd, idx_card, 1, 1, DELITEM_NORMAL, LOG_TYPE_CARD) == 1 )
4176 {// failed
4177 clif->insert_card(sd,idx_equip,idx_card,1);
4178 }
4179 else
4180 {// success
4181 int i;
4182 ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0);
4183 if (i == sd->inventory_data[idx_equip]->slot)
4184 return 0; // no free slots
4185 logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]);
4186 sd->status.inventory[idx_equip].card[i] = nameid;
4187 logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]);
4188 clif->insert_card(sd,idx_equip,idx_card,0);
4189 return 1;
4190 }
4191
4192 return 0;
4193}
4194
4195//
4196// Items
4197//
4198
4199/*==========================================
4200 * Update buying value by skills
4201 *------------------------------------------*/
4202int pc_modifybuyvalue(struct map_session_data *sd, int orig_value)
4203{
4204 int skill_lv, rate1 = 0, rate2 = 0;
4205 if (orig_value <= 0)
4206 return 0;
4207 if ((skill_lv=pc->checkskill(sd,MC_DISCOUNT)) > 0) // merchant discount
4208 rate1 = 5+skill_lv*2-((skill_lv==10)? 1:0);
4209 if ((skill_lv=pc->checkskill(sd,RG_COMPULSION)) > 0) // rogue discount
4210 rate2 = 5+skill_lv*4;
4211 if (rate1 < rate2)
4212 rate1 = rate2;
4213 if (rate1 != 0)
4214 orig_value = apply_percentrate(orig_value, 100-rate1, 100);
4215 if (orig_value < 1)
4216 orig_value = 1;
4217 return orig_value;
4218}
4219
4220/*==========================================
4221 * Update selling value by skills
4222 *------------------------------------------*/
4223int pc_modifysellvalue(struct map_session_data *sd, int orig_value)
4224{
4225 int skill_lv, rate = 0;
4226 if (orig_value <= 0)
4227 return 0;
4228 if ((skill_lv=pc->checkskill(sd,MC_OVERCHARGE)) > 0) //OverCharge
4229 rate = 5+skill_lv*2-((skill_lv==10)? 1:0);
4230 if (rate != 0)
4231 orig_value = apply_percentrate(orig_value, 100+rate, 100);
4232 if (orig_value < 1)
4233 orig_value = 1;
4234 return orig_value;
4235}
4236
4237/*==========================================
4238 * Checking if we have enough place on inventory for new item
4239 * Make sure to take 30k as limit (for client I guess)
4240 *------------------------------------------*/
4241int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
4242{
4243 int i;
4244 struct item_data* data;
4245
4246 nullpo_ret(sd);
4247
4248 if(amount > MAX_AMOUNT)
4249 return ADDITEM_OVERAMOUNT;
4250
4251 data = itemdb->search(nameid);
4252
4253 if(!itemdb->isstackable2(data))
4254 return ADDITEM_NEW;
4255
4256 if( data->stack.inventory && amount > data->stack.amount )
4257 return ADDITEM_OVERAMOUNT;
4258
4259 for(i=0;i<MAX_INVENTORY;i++){
4260 // FIXME: This does not consider the checked item's cards, thus could check a wrong slot for stackability.
4261 if(sd->status.inventory[i].nameid==nameid){
4262 if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
4263 return ADDITEM_OVERAMOUNT;
4264 return ADDITEM_EXIST;
4265 }
4266 }
4267
4268 return ADDITEM_NEW;
4269}
4270
4271/*==========================================
4272 * Return number of available place in inventory
4273 * Each non stackable item will reduce place by 1
4274 *------------------------------------------*/
4275int pc_inventoryblank(struct map_session_data *sd)
4276{
4277 int i,b;
4278
4279 nullpo_ret(sd);
4280
4281 for(i=0,b=0;i<MAX_INVENTORY;i++){
4282 if(sd->status.inventory[i].nameid==0)
4283 b++;
4284 }
4285
4286 return b;
4287}
4288
4289/*==========================================
4290 * attempts to remove zeny from player (sd)
4291 *------------------------------------------*/
4292int pc_payzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd)
4293{
4294 nullpo_retr(-1,sd);
4295
4296 zeny = cap_value(zeny,-MAX_ZENY,MAX_ZENY); //prevent command UB
4297 if( zeny < 0 )
4298 {
4299 ShowError("pc_payzeny: Paying negative Zeny (zeny=%d, account_id=%d, char_id=%d).\n", zeny, sd->status.account_id, sd->status.char_id);
4300 return 1;
4301 }
4302
4303 if( sd->status.zeny < zeny )
4304 return 1; //Not enough.
4305
4306 sd->status.zeny -= zeny;
4307 clif->updatestatus(sd,SP_ZENY);
4308
4309 if(!tsd) tsd = sd;
4310 logs->zeny(sd, type, tsd, -zeny);
4311 if( zeny > 0 && sd->state.showzeny ) {
4312 char output[255];
4313 sprintf(output, "Removed %dz.", zeny);
4314 clif_disp_onlyself(sd, output);
4315 }
4316
4317 return 0;
4318}
4319/*==========================================
4320 * Cash Shop
4321 *------------------------------------------*/
4322
4323int pc_paycash(struct map_session_data *sd, int price, int points)
4324{
4325 int cash;
4326 nullpo_retr(-1,sd);
4327
4328 points = cap_value(points,-MAX_ZENY,MAX_ZENY); //prevent command UB
4329 if( price < 0 || points < 0 )
4330 {
4331 ShowError("pc_paycash: Paying negative points (price=%d, points=%d, account_id=%d, char_id=%d).\n", price, points, sd->status.account_id, sd->status.char_id);
4332 return -2;
4333 }
4334
4335 if( points > price )
4336 {
4337 ShowWarning("pc_paycash: More kafra points provided than needed (price=%d, points=%d, account_id=%d, char_id=%d).\n", price, points, sd->status.account_id, sd->status.char_id);
4338 points = price;
4339 }
4340
4341 cash = price-points;
4342
4343 if( sd->cashPoints < cash || sd->kafraPoints < points )
4344 {
4345 ShowError("pc_paycash: Not enough points (cash=%d, kafra=%d) to cover the price (cash=%d, kafra=%d) (account_id=%d, char_id=%d).\n", sd->cashPoints, sd->kafraPoints, cash, points, sd->status.account_id, sd->status.char_id);
4346 return -1;
4347 }
4348
4349 pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints-cash);
4350 pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints-points);
4351
4352 if( battle_config.cashshop_show_points )
4353 {
4354 char output[128];
4355 sprintf(output, msg_sd(sd,504), points, cash, sd->kafraPoints, sd->cashPoints);
4356 clif_disp_onlyself(sd, output);
4357 }
4358 return cash+points;
4359}
4360
4361int pc_getcash(struct map_session_data *sd, int cash, int points)
4362{
4363 char output[128];
4364 nullpo_retr(-1,sd);
4365
4366 cash = cap_value(cash,-MAX_ZENY,MAX_ZENY); //prevent command UB
4367 points = cap_value(points,-MAX_ZENY,MAX_ZENY); //prevent command UB
4368 if( cash > 0 )
4369 {
4370 if( cash > MAX_ZENY-sd->cashPoints )
4371 {
4372 ShowWarning("pc_getcash: Cash point overflow (cash=%d, have cash=%d, account_id=%d, char_id=%d).\n", cash, sd->cashPoints, sd->status.account_id, sd->status.char_id);
4373 cash = MAX_ZENY-sd->cashPoints;
4374 }
4375
4376 pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints+cash);
4377
4378 if( battle_config.cashshop_show_points )
4379 {
4380 sprintf(output, msg_sd(sd,505), cash, sd->cashPoints);
4381 clif_disp_onlyself(sd, output);
4382 }
4383 return cash;
4384 }
4385 else if( cash < 0 )
4386 {
4387 ShowError("pc_getcash: Obtaining negative cash points (cash=%d, account_id=%d, char_id=%d).\n", cash, sd->status.account_id, sd->status.char_id);
4388 return -1;
4389 }
4390
4391 if( points > 0 )
4392 {
4393 if( points > MAX_ZENY-sd->kafraPoints )
4394 {
4395 ShowWarning("pc_getcash: Kafra point overflow (points=%d, have points=%d, account_id=%d, char_id=%d).\n", points, sd->kafraPoints, sd->status.account_id, sd->status.char_id);
4396 points = MAX_ZENY-sd->kafraPoints;
4397 }
4398
4399 pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints+points);
4400
4401 if( battle_config.cashshop_show_points )
4402 {
4403 sprintf(output, msg_sd(sd,506), points, sd->kafraPoints);
4404 clif_disp_onlyself(sd, output);
4405 }
4406 return points;
4407 }
4408 else if( points < 0 )
4409 {
4410 ShowError("pc_getcash: Obtaining negative kafra points (points=%d, account_id=%d, char_id=%d).\n", points, sd->status.account_id, sd->status.char_id);
4411 return -1;
4412 }
4413 return -2; //shouldn't happen but jsut in case
4414}
4415
4416/*==========================================
4417 * Attempts to give zeny to player (sd)
4418 * tsd (optional) from who for log (if null take sd)
4419 *------------------------------------------*/
4420int pc_getzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd)
4421{
4422 nullpo_retr(-1,sd);
4423
4424 zeny = cap_value(zeny,-MAX_ZENY,MAX_ZENY); //prevent command UB
4425 if( zeny < 0 )
4426 {
4427 ShowError("pc_getzeny: Obtaining negative Zeny (zeny=%d, account_id=%d, char_id=%d).\n", zeny, sd->status.account_id, sd->status.char_id);
4428 return 1;
4429 }
4430
4431 if( zeny > MAX_ZENY - sd->status.zeny )
4432 zeny = MAX_ZENY - sd->status.zeny;
4433
4434 sd->status.zeny += zeny;
4435 clif->updatestatus(sd,SP_ZENY);
4436
4437 if(!tsd) tsd = sd;
4438 logs->zeny(sd, type, tsd, zeny);
4439 if( zeny > 0 && sd->state.showzeny ) {
4440 char output[255];
4441 sprintf(output, "Gained %dz.", zeny);
4442 clif_disp_onlyself(sd, output);
4443 }
4444
4445 return 0;
4446}
4447
4448/**
4449 * Searches for the specified item ID in inventory and return its inventory index.
4450 *
4451 * If the item is found, the returned value is guaranteed to be a valid index
4452 * (non-negative, smaller than MAX_INVENTORY).
4453 *
4454 * @param sd Character to search on.
4455 * @param item_id The item ID to search.
4456 * @return the inventory index of the first instance of the requested item.
4457 * @retval INDEX_NOT_FOUND if the item wasn't found.
4458 */
4459int pc_search_inventory(struct map_session_data *sd, int item_id) {
4460 int i;
4461 nullpo_retr(INDEX_NOT_FOUND, sd);
4462
4463 ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == item_id && (sd->status.inventory[i].amount > 0 || item_id == 0) );
4464 return ( i < MAX_INVENTORY ) ? i : INDEX_NOT_FOUND;
4465}
4466
4467/*==========================================
4468 * Attempt to add a new item to inventory.
4469 * Return:
4470 * 0 = success
4471 * 1 = invalid itemid not found or negative amount
4472 * 2 = overweight
4473 * 3 = ?
4474 * 4 = no free place found
4475 * 5 = max amount reached
4476 * 6 = ?
4477 * 7 = stack limitation
4478 *------------------------------------------*/
4479int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type)
4480{
4481 struct item_data *data;
4482 int i;
4483 unsigned int w;
4484
4485 nullpo_retr(1, sd);
4486 nullpo_retr(1, item_data);
4487
4488 if( item_data->nameid <= 0 || amount <= 0 )
4489 return 1;
4490 if( amount > MAX_AMOUNT )
4491 return 5;
4492
4493 data = itemdb->search(item_data->nameid);
4494
4495 if( data->stack.inventory && amount > data->stack.amount )
4496 {// item stack limitation
4497 return 7;
4498 }
4499
4500 w = data->weight*amount;
4501 if(sd->weight + w > sd->max_weight)
4502 return 2;
4503
4504 if( item_data->bound ) {
4505 switch( (enum e_item_bound_type)item_data->bound ) {
4506 case IBT_CHARACTER:
4507 case IBT_ACCOUNT:
4508 break; /* no restrictions */
4509 case IBT_PARTY:
4510 if( !sd->status.party_id ) {
4511 ShowError("pc_additem: can't add party_bound item to character without party!\n");
4512 ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid);
4513 return 7;/* need proper code? */
4514 }
4515 break;
4516 case IBT_GUILD:
4517 if( !sd->status.guild_id ) {
4518 ShowError("pc_additem: can't add guild_bound item to character without guild!\n");
4519 ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid);
4520 return 7;/* need proper code? */
4521 }
4522 break;
4523 }
4524 }
4525
4526 i = MAX_INVENTORY;
4527
4528 // Stackable | Non Rental
4529 if( itemdb->isstackable2(data) && item_data->expire_time == 0 ) {
4530 for( i = 0; i < MAX_INVENTORY; i++ ) {
4531 if( sd->status.inventory[i].nameid == item_data->nameid &&
4532 sd->status.inventory[i].bound == item_data->bound &&
4533 sd->status.inventory[i].expire_time == 0 &&
4534 sd->status.inventory[i].unique_id == item_data->unique_id &&
4535 memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) {
4536 if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
4537 return 5;
4538 sd->status.inventory[i].amount += amount;
4539 clif->additem(sd,i,amount,0);
4540 break;
4541 }
4542 }
4543 }
4544
4545 if ( i >= MAX_INVENTORY ) {
4546 i = pc->search_inventory(sd,0);
4547 if (i == INDEX_NOT_FOUND)
4548 return 4;
4549
4550 memcpy(&sd->status.inventory[i], item_data, sizeof(sd->status.inventory[0]));
4551 // clear equip and favorite fields first, just in case
4552 if( item_data->equip )
4553 sd->status.inventory[i].equip = 0;
4554 if( item_data->favorite )
4555 sd->status.inventory[i].favorite = 0;
4556
4557 sd->status.inventory[i].amount = amount;
4558 sd->inventory_data[i] = data;
4559 clif->additem(sd,i,amount,0);
4560 }
4561
4562 if( ( !itemdb->isstackable2(data) || data->flag.force_serial || data->type == IT_CASH) && !item_data->unique_id )
4563 sd->status.inventory[i].unique_id = itemdb->unique_id(sd);
4564
4565 logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]);
4566
4567 sd->weight += w;
4568 clif->updatestatus(sd,SP_WEIGHT);
4569 //Auto-equip
4570 if(data->flag.autoequip)
4571 pc->equipitem(sd, i, data->equip);
4572
4573 /* rental item check */
4574 if( item_data->expire_time ) {
4575 if( time(NULL) > item_data->expire_time ) {
4576 pc->rental_expire(sd,i);
4577 } else {
4578 int seconds = (int)( item_data->expire_time - time(NULL) );
4579 clif->rental_time(sd->fd, sd->status.inventory[i].nameid, seconds);
4580 pc->inventory_rental_add(sd, seconds);
4581 }
4582 }
4583
4584 return 0;
4585}
4586
4587/*==========================================
4588 * Remove an item at index n from inventory by amount.
4589 * Parameters :
4590 * @type
4591 * 1 : don't notify deletion
4592 * 2 : don't notify weight change
4593 * reason: @see enum delitem_reason
4594 * Return:
4595 * 0 = success
4596 * 1 = invalid itemid or negative amount
4597 *------------------------------------------*/
4598int pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type)
4599{
4600 nullpo_retr(1, sd);
4601 Assert_retr(1, n >= 0 && n < MAX_INVENTORY);
4602
4603 if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
4604 return 1;
4605
4606 logs->pick_pc(sd, log_type, -amount, &sd->status.inventory[n],sd->inventory_data[n]);
4607
4608 sd->status.inventory[n].amount -= amount;
4609 sd->weight -= sd->inventory_data[n]->weight*amount ;
4610 if( sd->status.inventory[n].amount <= 0 ){
4611 if(sd->status.inventory[n].equip)
4612 pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
4613 memset(&sd->status.inventory[n],0,sizeof(sd->status.inventory[0]));
4614 sd->inventory_data[n] = NULL;
4615 }
4616 if(!(type&1))
4617 clif->delitem(sd,n,amount,reason);
4618 if(!(type&2))
4619 clif->updatestatus(sd,SP_WEIGHT);
4620
4621 return 0;
4622}
4623
4624/*==========================================
4625 * Attempt to drop an item.
4626 * Return:
4627 * 0 = fail
4628 * 1 = success
4629 *------------------------------------------*/
4630int pc_dropitem(struct map_session_data *sd,int n,int amount)
4631{
4632 nullpo_retr(1, sd);
4633
4634 if(n < 0 || n >= MAX_INVENTORY)
4635 return 0;
4636
4637 if(amount <= 0)
4638 return 0;
4639
4640 if(sd->status.inventory[n].nameid <= 0 ||
4641 sd->status.inventory[n].amount <= 0 ||
4642 sd->status.inventory[n].amount < amount ||
4643 sd->state.trading || sd->state.vending ||
4644 !sd->inventory_data[n] //pc->delitem would fail on this case.
4645 )
4646 return 0;
4647
4648 if( map->list[sd->bl.m].flag.nodrop ) {
4649 clif->message (sd->fd, msg_sd(sd,271)); // You can't drop items in this map
4650 return 0;
4651 }
4652
4653 if( !pc->candrop(sd,&sd->status.inventory[n]) )
4654 {
4655 clif->message (sd->fd, msg_sd(sd,263)); // This item cannot be dropped.
4656 return 0;
4657 }
4658
4659 if (!map->addflooritem(&sd->bl, &sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2))
4660 return 0;
4661
4662 pc->delitem(sd, n, amount, 1, DELITEM_NORMAL, LOG_TYPE_PICKDROP_PLAYER);
4663 clif->dropitem(sd, n, amount);
4664 return 1;
4665}
4666
4667/*==========================================
4668 * Attempt to pick up an item.
4669 * Return:
4670 * 0 = fail
4671 * 1 = success
4672 *------------------------------------------*/
4673int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
4674{
4675 int flag=0;
4676 int64 tick = timer->gettick();
4677 struct party_data *p=NULL;
4678
4679 nullpo_ret(sd);
4680 nullpo_ret(fitem);
4681
4682 if(!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skill_id!=BS_GREED)
4683 return 0; // Distance is too far
4684
4685 if( pc_has_permission(sd,PC_PERM_DISABLE_PICK_UP) )
4686 return 0;
4687
4688 if (sd->status.party_id)
4689 p = party->search(sd->status.party_id);
4690
4691 if (fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) {
4692 struct map_session_data *first_sd = map->charid2sd(fitem->first_get_charid);
4693 if (DIFF_TICK(tick,fitem->first_get_tick) < 0) {
4694 if (!(p && p->party.item&1 &&
4695 first_sd && first_sd->status.party_id == sd->status.party_id
4696 ))
4697 return 0;
4698 } else if (fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) {
4699 struct map_session_data *second_sd = map->charid2sd(fitem->second_get_charid);
4700 if (DIFF_TICK(tick, fitem->second_get_tick) < 0) {
4701 if (!(p && p->party.item&1 &&
4702 ((first_sd && first_sd->status.party_id == sd->status.party_id) ||
4703 (second_sd && second_sd->status.party_id == sd->status.party_id))
4704 ))
4705 return 0;
4706 } else if (fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id) {
4707 struct map_session_data *third_sd = map->charid2sd(fitem->third_get_charid);
4708 if (DIFF_TICK(tick,fitem->third_get_tick) < 0) {
4709 if (!(p && p->party.item&1 &&
4710 ((first_sd && first_sd->status.party_id == sd->status.party_id) ||
4711 (second_sd && second_sd->status.party_id == sd->status.party_id) ||
4712 (third_sd && third_sd->status.party_id == sd->status.party_id))
4713 ))
4714 return 0;
4715 }
4716 }
4717 }
4718 }
4719
4720 //This function takes care of giving the item to whoever should have it, considering party-share options.
4721 if ((flag = party->share_loot(p,sd,&fitem->item_data, fitem->first_get_charid))) {
4722 clif->additem(sd,0,0,flag);
4723 return 1;
4724 }
4725
4726 //Display pickup animation.
4727 pc_stop_attack(sd);
4728 clif->takeitem(&sd->bl,&fitem->bl);
4729 map->clearflooritem(&fitem->bl);
4730 return 1;
4731}
4732
4733/*==========================================
4734 * Check if item is usable.
4735 * Return:
4736 * 0 = no
4737 * 1 = yes
4738 *------------------------------------------*/
4739int pc_isUseitem(struct map_session_data *sd,int n)
4740{
4741 struct item_data *item;
4742 int nameid;
4743
4744 nullpo_ret(sd);
4745 Assert_ret(n >= 0 && n < MAX_INVENTORY);
4746
4747 item = sd->inventory_data[n];
4748 nameid = sd->status.inventory[n].nameid;
4749
4750 if( item == NULL )
4751 return 0;
4752 //Not consumable item
4753 if (!itemdb->is_item_usable(item))
4754 return 0;
4755 if( !item->script ) //if it has no script, you can't really consume it!
4756 return 0;
4757
4758 if ((item->item_usage.flag&INR_SITTING) && (pc_issit(sd) == 1) && (pc_get_group_level(sd) < item->item_usage.override)) {
4759 clif->msgtable(sd, MSG_ITEM_NEED_STANDING);
4760 //clif->messagecolor_self(sd->fd, COLOR_WHITE, msg_txt(1474));
4761 return 0; // You cannot use this item while sitting.
4762 }
4763
4764 if (sd->state.storage_flag != STORAGE_FLAG_CLOSED && item->type != IT_CASH) {
4765 clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1475));
4766 return 0; // You cannot use this item while storage is open.
4767 }
4768
4769 switch( nameid ) { // TODO: Is there no better way to handle this, other than hardcoding item IDs?
4770 case ITEMID_ANODYNE:
4771 if( map_flag_gvg2(sd->bl.m) )
4772 return 0;
4773 /* Fall through */
4774 case ITEMID_ALOEBERA:
4775 if( pc_issit(sd) )
4776 return 0;
4777 break;
4778 case ITEMID_WING_OF_FLY:
4779 case ITEMID_GIANT_FLY_WING:
4780 if( map->list[sd->bl.m].flag.noteleport || map_flag_gvg2(sd->bl.m) ) {
4781 clif->skill_mapinfomessage(sd,0);
4782 return 0;
4783 }
4784 /* Fall through */
4785 case ITEMID_WING_OF_BUTTERFLY:
4786 case ITEMID_DUN_TELE_SCROLL1:
4787 case ITEMID_DUN_TELE_SCROLL2:
4788 case ITEMID_WOB_RUNE: // Yellow Butterfly Wing
4789 case ITEMID_WOB_SCHWALTZ: // Green Butterfly Wing
4790 case ITEMID_WOB_RACHEL: // Red Butterfly Wing
4791 case ITEMID_WOB_LOCAL: // Blue Butterfly Wing
4792 case ITEMID_SIEGE_TELEPORT_SCROLL:
4793 if( sd->duel_group && !battle_config.duel_allow_teleport ) {
4794 clif->message(sd->fd, msg_sd(sd,863)); // "Duel: Can't use this item in duel."
4795 return 0;
4796 }
4797 if( nameid != ITEMID_WING_OF_FLY && nameid != ITEMID_GIANT_FLY_WING && map->list[sd->bl.m].flag.noreturn )
4798 return 0;
4799 break;
4800 case ITEMID_BRANCH_OF_DEAD_TREE:
4801 case ITEMID_RED_POUCH_OF_SURPRISE:
4802 case ITEMID_BLOODY_DEAD_BRANCH:
4803 case ITEMID_PORING_BOX:
4804 if( map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m) )
4805 return 0;
4806 break;
4807 case ITEMID_BUBBLE_GUM:
4808 case ITEMID_COMP_BUBBLE_GUM:
4809 if( sd->sc.data[SC_CASH_RECEIVEITEM] )
4810 return 0;
4811 break;
4812 case ITEMID_BATTLE_MANUAL:
4813 case ITEMID_COMP_BATTLE_MANUAL:
4814 case ITEMID_THICK_MANUAL50:
4815 case ITEMID_NOBLE_NAMEPLATE:
4816 case ITEMID_BATTLE_MANUAL25:
4817 case ITEMID_BATTLE_MANUAL100:
4818 case ITEMID_BATTLE_MANUAL_X3:
4819 if( sd->sc.data[SC_CASH_PLUSEXP] )
4820 return 0;
4821 break;
4822 case ITEMID_JOB_MANUAL50:
4823 if( sd->sc.data[SC_CASH_PLUSONLYJOBEXP] )
4824 return 0;
4825 break;
4826
4827 // Mercenary Items
4828 case ITEMID_MERCENARY_RED_POTION:
4829 case ITEMID_MERCENARY_BLUE_POTION:
4830 case ITEMID_M_CENTER_POTION:
4831 case ITEMID_M_AWAKENING_POTION:
4832 case ITEMID_M_BERSERK_POTION:
4833 if( sd->md == NULL || sd->md->db == NULL )
4834 return 0;
4835 if (sd->md->sc.data[SC_BERSERK])
4836 return 0;
4837 if( nameid == ITEMID_M_AWAKENING_POTION && sd->md->db->lv < 40 )
4838 return 0;
4839 if( nameid == ITEMID_M_BERSERK_POTION && sd->md->db->lv < 80 )
4840 return 0;
4841 break;
4842
4843 case ITEMID_NEURALIZER:
4844 if( !map->list[sd->bl.m].flag.reset )
4845 return 0;
4846 break;
4847 }
4848
4849 if( nameid >= ITEMID_BOW_MERCENARY_SCROLL1 && nameid <= ITEMID_SPEARMERCENARY_SCROLL10 && sd->md != NULL ) // Mercenary Scrolls
4850 return 0;
4851
4852 /**
4853 * Only Rune Knights may use runes
4854 **/
4855 if( itemdb_is_rune(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT )
4856 return 0;
4857 /**
4858 * Only GCross may use poisons
4859 **/
4860 else if( itemdb_is_poison(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_GUILLOTINE_CROSS )
4861 return 0;
4862
4863 if( item->package || item->group ) {
4864 if (pc_is90overweight(sd)) {
4865 clif->msgtable(sd, MSG_ITEM_CANT_OBTAIN_WEIGHT);
4866 return 0;
4867 }
4868 if (!pc->inventoryblank(sd)) {
4869 clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1477));
4870 return 0;
4871 }
4872 }
4873
4874 //Gender check
4875 if(item->sex != 2 && sd->status.sex != item->sex)
4876 return 0;
4877 //Required level check
4878 if (item->elv && sd->status.base_level < item->elv) {
4879 clif->msgtable(sd, MSG_ITEM_CANT_USE_LVL);
4880 return 0;
4881 }
4882
4883 if (item->elvmax && sd->status.base_level > item->elvmax) {
4884 clif->msgtable(sd, MSG_ITEM_CANT_USE_LVL);
4885 return 0;
4886 }
4887
4888 //Not equipable by class. [Skotlex]
4889 if (!(
4890 (1ULL<<(sd->class_&MAPID_BASEMASK)) &
4891 (item->class_base[(sd->class_&JOBL_2_1) ? 1 : ((sd->class_&JOBL_2_2) ? 2 : 0)])
4892 ))
4893 return 0;
4894
4895 //Not usable by upper class. [Haru]
4896 while( 1 ) {
4897 // Normal classes (no upper, no baby, no third classes)
4898 if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
4899#ifdef RENEWAL
4900 // Upper classes (no third classes)
4901 if( item->class_upper&ITEMUPPER_UPPER && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) break;
4902#else
4903 //pre-re has no use for the extra, so we maintain the previous for backwards compatibility
4904 if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
4905#endif
4906 // Baby classes (no third classes)
4907 if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) break;
4908 // Third classes (no upper, no baby classes)
4909 if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) ) break;
4910 // Upper third classes
4911 if( item->class_upper&ITEMUPPER_THURDUPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break;
4912 // Baby third classes
4913 if( item->class_upper&ITEMUPPER_THIRDBABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break;
4914 return 0;
4915 }
4916
4917 return 1;
4918}
4919
4920/*==========================================
4921 * Last checks to use an item.
4922 * Return:
4923 * 0 = fail
4924 * 1 = success
4925 *------------------------------------------*/
4926int pc_useitem(struct map_session_data *sd,int n) {
4927 int64 tick = timer->gettick();
4928 int amount, nameid, i;
4929 bool removeItem = false;
4930
4931 nullpo_ret(sd);
4932 Assert_ret(n >= 0 && n < MAX_INVENTORY);
4933
4934 if( sd->npc_id || sd->state.workinprogress&1 ){
4935 /* TODO: add to clif->messages enum */
4936#ifdef RENEWAL
4937 clif->msgtable(sd, MSG_NPC_WORK_IN_PROGRESS); // TODO look for the client date that has this message.
4938#endif
4939 return 0;
4940 }
4941
4942 if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 )
4943 return 0;
4944
4945 if( !pc->isUseitem(sd,n) )
4946 return 0;
4947
4948 // Store information for later use before it is lost (via pc->delitem) [Paradox924X]
4949 nameid = sd->inventory_data[n]->nameid;
4950
4951 if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING)
4952 return 0;
4953
4954 // Statuses that don't let the player use items
4955 if (sd->sc.count && (
4956 sd->sc.data[SC_BERSERK] ||
4957 (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) ||
4958 sd->sc.data[SC_TRICKDEAD] ||
4959 sd->sc.data[SC_HIDING] ||
4960 sd->sc.data[SC__SHADOWFORM] ||
4961 sd->sc.data[SC__INVISIBILITY] ||
4962 sd->sc.data[SC__MANHOLE] ||
4963 sd->sc.data[SC_KG_KAGEHUMI] ||
4964 sd->sc.data[SC_WHITEIMPRISON] ||
4965 sd->sc.data[SC_DEEP_SLEEP] ||
4966 sd->sc.data[SC_SATURDAY_NIGHT_FEVER] ||
4967 sd->sc.data[SC_COLD] ||
4968 pc_ismuted(&sd->sc, MANNER_NOITEM)
4969 ))
4970 return 0;
4971
4972 //Prevent mass item usage. [Skotlex]
4973 if( DIFF_TICK(sd->canuseitem_tick, tick) > 0 ||
4974 (itemdb_iscashfood(nameid) && DIFF_TICK(sd->canusecashfood_tick, tick) > 0)
4975 )
4976 return 0;
4977
4978 /* Items with delayed consume are not meant to work while in mounts except reins of mount(12622) */
4979 if( sd->inventory_data[n]->flag.delay_consume && nameid != ITEMID_REINS_OF_MOUNT ) {
4980 if( sd->sc.data[SC_ALL_RIDING] )
4981 return 0;
4982 else if( pc_issit(sd) )
4983 return 0;
4984 }
4985 //Since most delay-consume items involve using a "skill-type" target cursor,
4986 //perform a skill-use check before going through. [Skotlex]
4987 //resurrection was picked as testing skill, as a non-offensive, generic skill, it will do.
4988 //FIXME: Is this really needed here? It'll be checked in unit.c after all and this prevents skill items using when silenced [Inkfish]
4989 if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status->check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
4990 return 0;
4991
4992 if( sd->inventory_data[n]->delay > 0 ) {
4993 ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid );
4994 if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */
4995 ARR_FIND(0, MAX_ITEMDELAYS, i, !sd->item_delay[i].nameid );
4996 if( i < MAX_ITEMDELAYS ) {
4997 if( sd->item_delay[i].nameid ) {// found
4998 if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) {
4999 int e_tick = (int)(DIFF_TICK(sd->item_delay[i].tick, tick)/1000);
5000 clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, e_tick + 1); // [%d] seconds left until you can use
5001 return 0; // Delay has not expired yet
5002 }
5003 } else {// not yet used item (all slots are initially empty)
5004 sd->item_delay[i].nameid = nameid;
5005 }
5006 if (!(nameid == ITEMID_REINS_OF_MOUNT && pc_hasmount(sd)))
5007 sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay;
5008 } else {// should not happen
5009 ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%d, char_id=%d)\n", nameid, sd->status.char_id);
5010 }
5011 //clean up used delays so we can give room for more
5012 for(i = 0; i < MAX_ITEMDELAYS; i++) {
5013 if( DIFF_TICK(sd->item_delay[i].tick, tick) <= 0 ) {
5014 sd->item_delay[i].tick = 0;
5015 sd->item_delay[i].nameid = 0;
5016 }
5017 }
5018 }
5019
5020 /* on restricted maps the item is consumed but the effect is not used */
5021 for(i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++) {
5022 if( map->list[sd->bl.m].zone->disabled_items[i] == nameid ) {
5023 clif->msgtable(sd, MSG_ITEM_CANT_USE_AREA); // This item cannot be used within this area
5024 if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) {
5025 clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true);
5026 pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME);
5027 }
5028 return 0;
5029 }
5030 }
5031
5032 //Dead Branch & Bloody Branch & Porings Box
5033 if( nameid == ITEMID_BRANCH_OF_DEAD_TREE || nameid == ITEMID_BLOODY_DEAD_BRANCH || nameid == ITEMID_PORING_BOX )
5034 logs->branch(sd);
5035
5036 sd->itemid = sd->status.inventory[n].nameid;
5037 sd->itemindex = n;
5038 if(sd->catch_target_class != -1) //Abort pet catching.
5039 sd->catch_target_class = -1;
5040
5041 amount = sd->status.inventory[n].amount;
5042 //Check if the item is to be consumed immediately [Skotlex]
5043 if (sd->inventory_data[n]->flag.delay_consume || sd->inventory_data[n]->flag.keepafteruse)
5044 clif->useitemack(sd,n,amount,true);
5045 else {
5046 if (sd->status.inventory[n].expire_time == 0) {
5047 clif->useitemack(sd, n, amount - 1, true);
5048 removeItem = true;
5049 } else {
5050 clif->useitemack(sd, n, 0, false);
5051 }
5052 }
5053
5054 if(sd->status.inventory[n].card[0]==CARD0_CREATE &&
5055 pc->famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST))
5056 {
5057 script->potion_flag = 2; // Famous player's potions have 50% more efficiency
5058 if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ROGUE)
5059 script->potion_flag = 3; //Even more effective potions.
5060 }
5061
5062 //Update item use time.
5063 sd->canuseitem_tick = tick + battle_config.item_use_interval;
5064 if( itemdb_iscashfood(nameid) )
5065 sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval;
5066
5067 script->run_use_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
5068 script->potion_flag = 0;
5069
5070 if (removeItem)
5071 pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME);
5072 return 1;
5073}
5074
5075/*==========================================
5076 * Add item on cart for given index.
5077 * Return:
5078 * 0 = success
5079 * 1 = fail
5080 *------------------------------------------*/
5081int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type)
5082{
5083 struct item_data *data;
5084 int i,w;
5085
5086 nullpo_retr(1, sd);
5087 nullpo_retr(1, item_data);
5088
5089 if(item_data->nameid <= 0 || amount <= 0)
5090 return 1;
5091 data = itemdb->search(item_data->nameid);
5092
5093 if( data->stack.cart && amount > data->stack.amount )
5094 {// item stack limitation
5095 return 1;
5096 }
5097
5098 if (!itemdb_cancartstore(item_data, pc_get_group_level(sd)) || (item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd))) {
5099 // Check item trade restrictions
5100 clif->message (sd->fd, msg_sd(sd,264)); // This item cannot be stored.
5101 return 1;/* TODO: there is no official response to this? */
5102 }
5103
5104 if( (w = data->weight*amount) + sd->cart_weight > sd->cart_weight_max )
5105 return 1;
5106
5107 i = MAX_CART;
5108 if( itemdb->isstackable2(data) && !item_data->expire_time )
5109 {
5110 ARR_FIND( 0, MAX_CART, i,
5111 sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound &&
5112 sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
5113 sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] );
5114 };
5115
5116 if( i < MAX_CART && item_data->unique_id == sd->status.cart[i].unique_id)
5117 {// item already in cart, stack it
5118 if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) )
5119 return 2; // no room
5120
5121 sd->status.cart[i].amount+=amount;
5122 clif->cart_additem(sd,i,amount,0);
5123 }
5124 else
5125 {// item not stackable or not present, add it
5126 ARR_FIND( 0, MAX_CART, i, sd->status.cart[i].nameid == 0 );
5127 if( i == MAX_CART )
5128 return 2; // no room
5129
5130 memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0]));
5131 sd->status.cart[i].amount=amount;
5132 sd->cart_num++;
5133 clif->cart_additem(sd,i,amount,0);
5134 }
5135 sd->status.cart[i].favorite = 0;/* clear */
5136 logs->pick_pc(sd, log_type, amount, &sd->status.cart[i],data);
5137
5138 sd->cart_weight += w;
5139 clif->updatestatus(sd,SP_CARTINFO);
5140
5141 return 0;
5142}
5143
5144/*==========================================
5145 * Delete item on cart for given index.
5146 * Return:
5147 * 0 = success
5148 * 1 = fail
5149 *------------------------------------------*/
5150int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_pick_type log_type) {
5151 struct item_data * data;
5152 nullpo_retr(1, sd);
5153 Assert_retr(1, n >= 0 && n < MAX_INVENTORY);
5154
5155 if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb->exists(sd->status.cart[n].nameid)) )
5156 return 1;
5157
5158 logs->pick_pc(sd, log_type, -amount, &sd->status.cart[n],data);
5159
5160 sd->status.cart[n].amount -= amount;
5161 sd->cart_weight -= data->weight*amount ;
5162 if(sd->status.cart[n].amount <= 0){
5163 memset(&sd->status.cart[n],0,sizeof(sd->status.cart[0]));
5164 sd->cart_num--;
5165 }
5166 if(!type) {
5167 clif->cart_delitem(sd,n,amount);
5168 clif->updatestatus(sd,SP_CARTINFO);
5169 }
5170
5171 return 0;
5172}
5173
5174/*==========================================
5175 * Transfer item from inventory to cart.
5176 * Return:
5177 * 0 = fail
5178 * 1 = succes
5179 *------------------------------------------*/
5180int pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
5181{
5182 struct item *item_data;
5183 int flag;
5184
5185 nullpo_ret(sd);
5186
5187 if (idx < 0 || idx >= MAX_INVENTORY) //Invalid index check [Skotlex]
5188 return 1;
5189
5190 item_data = &sd->status.inventory[idx];
5191
5192 if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending )
5193 return 1;
5194
5195 if( (flag = pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0 )
5196 return pc->delitem(sd, idx, amount, 0, DELITEM_TOCART, LOG_TYPE_NONE);
5197
5198 return flag;
5199}
5200
5201/*==========================================
5202 * Get number of item in cart.
5203 * Return:
5204 * -1 = itemid not found or no amount found
5205 * x = remaining itemid on cart after get
5206 *------------------------------------------*/
5207int pc_cartitem_amount(struct map_session_data* sd, int idx, int amount)
5208{
5209 struct item* item_data;
5210
5211 nullpo_retr(-1, sd);
5212 Assert_retr(-1, idx >= 0 && idx < MAX_CART);
5213
5214 item_data = &sd->status.cart[idx];
5215 if( item_data->nameid == 0 || item_data->amount == 0 )
5216 return -1;
5217
5218 return item_data->amount - amount;
5219}
5220
5221/*==========================================
5222 * Retrieve an item at index idx from cart.
5223 * Return:
5224 * 0 = player not found or (FIXME) succes (from pc->cart_delitem)
5225 * 1 = failure
5226 *------------------------------------------*/
5227int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
5228{
5229 struct item *item_data;
5230 int flag;
5231
5232 nullpo_ret(sd);
5233
5234 if (idx < 0 || idx >= MAX_CART) //Invalid index check [Skotlex]
5235 return 1;
5236
5237 item_data=&sd->status.cart[idx];
5238
5239 if(item_data->nameid==0 || amount < 1 || item_data->amount<amount || sd->state.vending )
5240 return 1;
5241
5242 if((flag = pc->additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0)
5243 return pc->cart_delitem(sd,idx,amount,0,LOG_TYPE_NONE);
5244
5245 return flag;
5246}
5247
5248void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type)
5249{
5250 int i;
5251
5252 nullpo_retv(sd);
5253 switch( type ) {
5254 /* both restricted to inventory */
5255 case IBT_PARTY:
5256 case IBT_CHARACTER:
5257 for( i = 0; i < MAX_INVENTORY; i++ ){
5258 if( sd->status.inventory[i].bound == type ) {
5259 pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_SKILLUSE, LOG_TYPE_OTHER); // FIXME: is this the correct reason flag?
5260 }
5261 }
5262 break;
5263 case IBT_ACCOUNT:
5264 ShowError("Helllo! You reached pc_bound_clear for IBT_ACCOUNT, unfortunately no scenario was expected for this!\n");
5265 break;
5266 case IBT_GUILD: {
5267 struct guild_storage *gstor = idb_get(gstorage->db,sd->status.guild_id);
5268
5269 for( i = 0; i < MAX_INVENTORY; i++ ){
5270 if(sd->status.inventory[i].bound == type) {
5271 if( gstor )
5272 gstorage->additem(sd,gstor,&sd->status.inventory[i],sd->status.inventory[i].amount);
5273 pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_SKILLUSE, gstor ? LOG_TYPE_GSTORAGE : LOG_TYPE_OTHER); // FIXME: is this the correct reason flag?
5274 }
5275 }
5276 if( gstor )
5277 gstorage->close(sd);
5278 }
5279 break;
5280 }
5281}
5282/*==========================================
5283 * Display item stolen msg to player sd
5284 *------------------------------------------*/
5285int pc_show_steal(struct block_list *bl,va_list ap)
5286{
5287 struct map_session_data *sd = NULL, *tsd = NULL;
5288 int itemid;
5289
5290 struct item_data *item=NULL;
5291 char output[100];
5292
5293 sd=va_arg(ap,struct map_session_data *);
5294 itemid=va_arg(ap,int);
5295
5296 nullpo_ret(bl);
5297 Assert_ret(bl->type == BL_PC);
5298 tsd = BL_UCAST(BL_PC, bl);
5299 nullpo_ret(sd);
5300
5301 if((item=itemdb->exists(itemid))==NULL)
5302 sprintf(output,"%s stole an Unknown Item (id: %i).",sd->status.name, itemid);
5303 else
5304 sprintf(output,"%s stole %s.",sd->status.name,item->jname);
5305 clif->message(tsd->fd, output);
5306
5307 return 0;
5308}
5309/*==========================================
5310 * Steal an item from bl (mob).
5311 * Return:
5312 * 0 = fail
5313 * 1 = succes
5314 *------------------------------------------*/
5315int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skill_lv)
5316{
5317 int i,itemid,flag;
5318 int rate;
5319 struct status_data *sd_status, *md_status;
5320 struct mob_data *md = BL_CAST(BL_MOB, bl);
5321 struct item tmp_item;
5322 struct item_data *data = NULL;
5323
5324 if (sd == NULL || md == NULL)
5325 return 0;
5326
5327 if(md->state.steal_flag == UCHAR_MAX || ( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check
5328 return 0;
5329
5330 sd_status= status->get_status_data(&sd->bl);
5331 md_status= status->get_status_data(bl);
5332
5333 if (md->master_id || md_status->mode&MD_BOSS || mob_is_treasure(md) ||
5334 map->list[bl->m].flag.nomobloot || // check noloot map flag [Lorky]
5335 (battle_config.skill_steal_max_tries && //Reached limit of steal attempts. [Lupus]
5336 md->state.steal_flag++ >= battle_config.skill_steal_max_tries)
5337 ) { //Can't steal from
5338 md->state.steal_flag = UCHAR_MAX;
5339 return 0;
5340 }
5341
5342 // base skill success chance (percentual)
5343 rate = (sd_status->dex - md_status->dex)/2 + skill_lv*6 + 4 + sd->bonus.add_steal_rate;
5344
5345 if( rate < 1 )
5346 return 0;
5347
5348 // Try dropping one item, in the order from first to last possible slot.
5349 // Droprate is affected by the skill success rate.
5350 for (i = 0; i < MAX_STEAL_DROP; i++) {
5351 if (md->db->dropitem[i].nameid == 0)
5352 continue;
5353 if ((data = itemdb->exists(md->db->dropitem[i].nameid)) == NULL)
5354 continue;
5355 if (rnd() % 10000 < apply_percentrate(md->db->dropitem[i].p, rate, 100))
5356 break;
5357 }
5358 if (i == MAX_STEAL_DROP)
5359 return 0;
5360
5361 itemid = md->db->dropitem[i].nameid;
5362 memset(&tmp_item,0,sizeof(tmp_item));
5363 tmp_item.nameid = itemid;
5364 tmp_item.amount = 1;
5365 tmp_item.identify = itemdb->isidentified2(data);
5366 flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER);
5367
5368 //TODO: Should we disable stealing when the item you stole couldn't be added to your inventory? Perhaps players will figure out a way to exploit this behaviour otherwise?
5369 md->state.steal_flag = UCHAR_MAX; //you can't steal from this mob any more
5370
5371 if(flag) { //Failed to steal due to overweight
5372 clif->additem(sd,0,0,flag);
5373 return 0;
5374 }
5375
5376 if(battle_config.show_steal_in_same_party)
5377 party->foreachsamemap(pc->show_steal,sd,AREA_SIZE,sd,tmp_item.nameid);
5378
5379 //Logs items, Stolen from mobs [Lupus]
5380 logs->pick_mob(md, LOG_TYPE_STEAL, -1, &tmp_item, data);
5381
5382 //A Rare Steal Global Announce by Lupus
5383 if(md->db->dropitem[i].p<=battle_config.rare_drop_announce) {
5384 char message[128];
5385 sprintf (message, msg_txt(542), sd->status.name, md->db->jname, data->jname, (float)md->db->dropitem[i].p / 100);
5386 //MSG: "'%s' stole %s's %s (chance: %0.02f%%)"
5387 intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT);
5388 }
5389 return 1;
5390}
5391
5392/**
5393 * Steals zeny from a monster through the RG_STEALCOIN skill.
5394 *
5395 * @param sd Source character
5396 * @param target Target monster
5397 * @param skill_lv Skill Level
5398 *
5399 * @return Amount of stolen zeny (0 in case of failure)
5400 */
5401int pc_steal_coin(struct map_session_data *sd, struct block_list *target, uint16 skill_lv)
5402{
5403 int rate;
5404 struct mob_data *md = BL_CAST(BL_MOB, target);
5405
5406 if (sd == NULL || md == NULL)
5407 return 0;
5408
5409 if (md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE] || md->status.mode&MD_BOSS)
5410 return 0;
5411
5412 if (mob_is_treasure(md))
5413 return 0;
5414
5415 rate = skill_lv * 10 + (sd->status.base_level - md->level) * 2 + sd->battle_status.dex / 2 + sd->battle_status.luk / 2;
5416 if(rnd()%1000 < rate) {
5417 int amount = md->level * skill_lv / 10 + md->level * 8 + rnd()%(md->level * 2 + 1); // mob_lv * skill_lv / 10 + random [mob_lv*8; mob_lv*10]
5418
5419 pc->getzeny(sd, amount, LOG_TYPE_STEAL, NULL);
5420 md->state.steal_coin_flag = 1;
5421 return amount;
5422 }
5423 return 0;
5424}
5425
5426/*==========================================
5427 * Set's a player position.
5428 * Return values:
5429 * 0 - Success.
5430 * 1 - Invalid map index.
5431 * 2 - Map not in this map-server, and failed to locate alternate map-server.
5432 *------------------------------------------*/
5433int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int y, clr_type clrtype) {
5434 int16 m;
5435
5436 nullpo_ret(sd);
5437
5438 if( !map_index || !mapindex_id2name(map_index) || ( m = map->mapindex2mapid(map_index) ) == -1 ) {
5439 ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", map_index);
5440 return 1;
5441 }
5442
5443 if( pc_isdead(sd) ) { //Revive dead people before warping them
5444 pc->setstand(sd);
5445 pc->setrestartvalue(sd,1);
5446 }
5447
5448 if( map->list[m].flag.src4instance ) {
5449 struct party_data *p;
5450 bool stop = false;
5451 int i = 0, j = 0;
5452
5453 if( sd->instances ) {
5454 for( i = 0; i < sd->instances; i++ ) {
5455 if( sd->instance[i] >= 0 ) {
5456 ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->instance[i]].map[j]].custom_name);
5457 if( j != instance->list[sd->instance[i]].num_map )
5458 break;
5459 }
5460 }
5461 if( i != sd->instances ) {
5462 m = instance->list[sd->instance[i]].map[j];
5463 map_index = map_id2index(m);
5464 stop = true;
5465 }
5466 }
5467 if ( !stop && sd->status.party_id && (p = party->search(sd->status.party_id)) != NULL && p->instances ) {
5468 for( i = 0; i < p->instances; i++ ) {
5469 if( p->instance[i] >= 0 ) {
5470 ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[p->instance[i]].map[j]].custom_name);
5471 if( j != instance->list[p->instance[i]].num_map )
5472 break;
5473 }
5474 }
5475 if( i != p->instances ) {
5476 m = instance->list[p->instance[i]].map[j];
5477 map_index = map_id2index(m);
5478 stop = true;
5479 }
5480 }
5481 if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) {
5482 for( i = 0; i < sd->guild->instances; i++ ) {
5483 if( sd->guild->instance[i] >= 0 ) {
5484 ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name);
5485 if( j != instance->list[sd->guild->instance[i]].num_map )
5486 break;
5487 }
5488 }
5489 if( i != sd->guild->instances ) {
5490 m = instance->list[sd->guild->instance[i]].map[j];
5491 map_index = map_id2index(m);
5492 //stop = true; Uncomment if adding new checks
5493 }
5494 }
5495
5496 /* we hit a instance, if empty we populate the spawn data */
5497 if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 &&
5498 instance->list[map->list[m].instance_id].respawn.x == 0 &&
5499 instance->list[map->list[m].instance_id].respawn.y == 0) {
5500 instance->list[map->list[m].instance_id].respawn.map = map_index;
5501 instance->list[map->list[m].instance_id].respawn.x = x;
5502 instance->list[map->list[m].instance_id].respawn.y = y;
5503 }
5504 }
5505
5506 sd->state.changemap = (sd->mapindex != map_index);
5507 sd->state.warping = 1;
5508 sd->state.workinprogress = 0;
5509 if( sd->state.changemap ) { // Misc map-changing settings
5510 int i;
5511 sd->state.pmap = sd->bl.m;
5512
5513 for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
5514 struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
5515 if (queue && queue->event_mapchange[0] != '\0') {
5516 pc->setregstr(sd, script->add_str("@Queue_Destination_Map$"), map->list[m].name);
5517 npc->event(sd, queue->event_mapchange, 0);
5518 }
5519 }
5520
5521 if( map->list[m].cell == (struct mapcell *)0xdeadbeaf )
5522 map->cellfromcache(&map->list[m]);
5523 if (sd->sc.count) { // Cancel some map related stuff.
5524 if (sd->sc.data[SC_JAILED])
5525 return 1; //You may not get out!
5526 status_change_end(&sd->bl, SC_CASH_BOSS_ALARM, INVALID_TIMER);
5527 status_change_end(&sd->bl, SC_WARM, INVALID_TIMER);
5528 status_change_end(&sd->bl, SC_SUN_COMFORT, INVALID_TIMER);
5529 status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER);
5530 status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER);
5531 status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER);
5532 status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);//Will later check if this is needed. [Rytech]
5533 status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER);
5534 status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
5535 status_change_end(&sd->bl, SC_STEALTHFIELD, INVALID_TIMER);
5536 if (sd->sc.data[SC_KNOWLEDGE]) {
5537 struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE];
5538 if (sce->timer != INVALID_TIMER)
5539 timer->delete(sce->timer, status->change_timer);
5540 sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status->change_timer, sd->bl.id, SC_KNOWLEDGE);
5541 }
5542 status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
5543 status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER);
5544 status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
5545 }
5546 for( i = 0; i < EQI_MAX; i++ ) {
5547 if( sd->equip_index[ i ] >= 0 )
5548 if( !pc->isequip( sd , sd->equip_index[ i ] ) )
5549 pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
5550 }
5551 if (battle_config.clear_unit_onwarp&BL_PC)
5552 skill->clear_unitgroup(&sd->bl);
5553 party->send_dot_remove(sd); //minimap dot fix [Kevin]
5554 guild->send_dot_remove(sd);
5555 bg->send_dot_remove(sd);
5556 if (sd->regen.state.gc)
5557 sd->regen.state.gc = 0;
5558 // make sure vending is allowed here
5559 if (sd->state.vending && map->list[m].flag.novending) {
5560 clif->message (sd->fd, msg_sd(sd,276)); // "You can't open a shop on this map"
5561 vending->close(sd);
5562 }
5563
5564 if (map->list[sd->bl.m].channel) {
5565 channel->leave(map->list[sd->bl.m].channel,sd);
5566 }
5567 }
5568
5569 if( m < 0 ) {
5570 uint32 ip;
5571 uint16 port;
5572 //if can't find any map-servers, just abort setting position.
5573 if(!sd->mapindex || map->mapname2ipport(map_index,&ip,&port))
5574 return 2;
5575
5576 if (sd->npc_id)
5577 npc->event_dequeue(sd);
5578 npc->script_event(sd, NPCE_LOGOUT);
5579 //remove from map, THEN change x/y coordinates
5580 unit->remove_map_pc(sd,clrtype);
5581 if (battle_config.player_warp_keep_direction == 0)
5582 sd->ud.dir = 0; // makes character face north
5583 sd->mapindex = map_index;
5584 sd->bl.x=x;
5585 sd->bl.y=y;
5586 pc->clean_skilltree(sd);
5587 chrif->save(sd,2);
5588 chrif->changemapserver(sd, ip, (short)port);
5589
5590 //Free session data from this map server [Kevin]
5591 unit->free_pc(sd);
5592
5593 return 0;
5594 }
5595
5596 if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) {
5597 ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(map_index),x,y);
5598 x = y = 0; // make it random
5599 }
5600
5601 if( x == 0 && y == 0 ) {// pick a random walkable cell
5602 do {
5603 x=rnd()%(map->list[m].xs-2)+1;
5604 y=rnd()%(map->list[m].ys-2)+1;
5605 } while(map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS));
5606 }
5607
5608 if (sd->state.vending && map->getcell(m, &sd->bl, x, y, CELL_CHKNOVENDING)) {
5609 clif->message (sd->fd, msg_sd(sd,204)); // "You can't open a shop on this cell."
5610 vending->close(sd);
5611 }
5612
5613 if (battle_config.player_warp_keep_direction == 0)
5614 sd->ud.dir = 0; // makes character face north
5615
5616 if(sd->bl.prev != NULL){
5617 unit->remove_map_pc(sd,clrtype);
5618 clif->changemap(sd,m,x,y); // [MouseJstr]
5619 } else if(sd->state.active)
5620 //Tag player for rewarping after map-loading is done. [Skotlex]
5621 sd->state.rewarp = 1;
5622
5623 sd->mapindex = map_index;
5624 sd->bl.m = m;
5625 sd->bl.x = sd->ud.to_x = x;
5626 sd->bl.y = sd->ud.to_y = y;
5627
5628 if( sd->status.guild_id > 0 && map->list[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris]
5629 struct guild_castle *gc = guild->mapindex2gc(sd->mapindex);
5630 if(gc && gc->guild_id == sd->status.guild_id)
5631 sd->regen.state.gc = 1;
5632 }
5633
5634 if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) {
5635 sd->pd->bl.m = m;
5636 sd->pd->bl.x = sd->pd->ud.to_x = x;
5637 sd->pd->bl.y = sd->pd->ud.to_y = y;
5638 sd->pd->ud.dir = sd->ud.dir;
5639 }
5640
5641 if( homun_alive(sd->hd) ) {
5642 sd->hd->bl.m = m;
5643 sd->hd->bl.x = sd->hd->ud.to_x = x;
5644 sd->hd->bl.y = sd->hd->ud.to_y = y;
5645 sd->hd->ud.dir = sd->ud.dir;
5646 }
5647
5648 if( sd->md ) {
5649 sd->md->bl.m = m;
5650 sd->md->bl.x = sd->md->ud.to_x = x;
5651 sd->md->bl.y = sd->md->ud.to_y = y;
5652 sd->md->ud.dir = sd->ud.dir;
5653 }
5654
5655 /* given autotrades have no clients you have to trigger this manually otherwise they get stuck in memory limbo bugreport:7495 */
5656 if( sd->state.autotrade )
5657 clif->pLoadEndAck(0,sd);
5658
5659 return 0;
5660}
5661
5662/*==========================================
5663 * Warp player sd to random location on current map.
5664 * May fail if no walkable cell found (1000 attempts).
5665 * Return:
5666 * 0 = fail or FIXME success (from pc->setpos)
5667 * x(1|2) = fail
5668 *------------------------------------------*/
5669int pc_randomwarp(struct map_session_data *sd, clr_type type) {
5670 int x,y,i=0;
5671 int16 m;
5672
5673 nullpo_ret(sd);
5674
5675 m=sd->bl.m;
5676
5677 if (map->list[sd->bl.m].flag.noteleport) //Teleport forbidden
5678 return 0;
5679
5680 do {
5681 x=rnd()%(map->list[m].xs-2)+1;
5682 y=rnd()%(map->list[m].ys-2)+1;
5683 } while (map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS) && (i++) < 1000 );
5684
5685 if (i < 1000)
5686 return pc->setpos(sd,map_id2index(sd->bl.m),x,y,type);
5687
5688 return 0;
5689}
5690
5691/*==========================================
5692 * Records a memo point at sd's current position
5693 * pos - entry to replace, (-1: shift oldest entry out)
5694 *------------------------------------------*/
5695int pc_memo(struct map_session_data* sd, int pos) {
5696 int skill_lv;
5697
5698 nullpo_ret(sd);
5699
5700 // check mapflags
5701 if( sd->bl.m >= 0 && (map->list[sd->bl.m].flag.nomemo || map->list[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) {
5702 clif->skill_mapinfomessage(sd, 1); // "Saved point cannot be memorized."
5703 return 0;
5704 }
5705
5706 // check inputs
5707 if( pos < -1 || pos >= MAX_MEMOPOINTS )
5708 return 0; // invalid input
5709
5710 // check required skill level
5711 skill_lv = pc->checkskill(sd, AL_WARP);
5712 if( skill_lv < 1 ) {
5713 clif->skill_memomessage(sd,2); // "You haven't learned Warp."
5714 return 0;
5715 }
5716 if( skill_lv < 2 || skill_lv - 2 < pos ) {
5717 clif->skill_memomessage(sd,1); // "Skill Level is not high enough."
5718 return 0;
5719 }
5720
5721 if( pos == -1 )
5722 {
5723 int i;
5724 // prevent memo-ing the same map multiple times
5725 ARR_FIND( 0, MAX_MEMOPOINTS, i, sd->status.memo_point[i].map == map_id2index(sd->bl.m) );
5726 memmove(&sd->status.memo_point[1], &sd->status.memo_point[0], (min(i,MAX_MEMOPOINTS-1))*sizeof(struct point));
5727 pos = 0;
5728 }
5729
5730 sd->status.memo_point[pos].map = map_id2index(sd->bl.m);
5731 sd->status.memo_point[pos].x = sd->bl.x;
5732 sd->status.memo_point[pos].y = sd->bl.y;
5733
5734 clif->skill_memomessage(sd, 0);
5735
5736 return 1;
5737}
5738
5739//
5740// Skills
5741//
5742/*==========================================
5743 * Return player sd skill_lv learned for given skill
5744 *------------------------------------------*/
5745int pc_checkskill(struct map_session_data *sd,uint16 skill_id) {
5746 uint16 index = 0;
5747 if(sd == NULL) return 0;
5748 if( skill_id >= GD_SKILLBASE && skill_id < GD_MAX ) {
5749 struct guild *g;
5750
5751 if( sd->status.guild_id>0 && (g=sd->guild)!=NULL)
5752 return guild->checkskill(g,skill_id);
5753 return 0;
5754 } else if(!(index = skill->get_index(skill_id)) || index >= ARRAYLENGTH(sd->status.skill) ) {
5755 ShowError("pc_checkskill: Invalid skill id %d (char_id=%d).\n", skill_id, sd->status.char_id);
5756 return 0;
5757 }
5758
5759 if(sd->status.skill[index].id == skill_id)
5760 return (sd->status.skill[index].lv);
5761
5762 return 0;
5763}
5764int pc_checkskill2(struct map_session_data *sd,uint16 index) {
5765 if(sd == NULL) return 0;
5766 if(index >= ARRAYLENGTH(sd->status.skill) ) {
5767 ShowError("pc_checkskill: Invalid skill index %d (char_id=%d).\n", index, sd->status.char_id);
5768 return 0;
5769 }
5770 if( skill->dbs->db[index].nameid >= GD_SKILLBASE && skill->dbs->db[index].nameid < GD_MAX ) {
5771 struct guild *g;
5772
5773 if( sd->status.guild_id>0 && (g=sd->guild)!=NULL)
5774 return guild->checkskill(g,skill->dbs->db[index].nameid);
5775 return 0;
5776 }
5777 if(sd->status.skill[index].id == skill->dbs->db[index].nameid)
5778 return (sd->status.skill[index].lv);
5779
5780 return 0;
5781}
5782
5783/*==========================================
5784 * Chk if we still have the correct weapon to continue the skill (actually status)
5785 * If not ending it
5786 * Return
5787 * 0 - No status found or all done
5788 *------------------------------------------*/
5789int pc_checkallowskill(struct map_session_data *sd)
5790{
5791 const enum sc_type scw_list[] = {
5792 SC_TWOHANDQUICKEN,
5793 SC_ONEHANDQUICKEN,
5794 SC_AURABLADE,
5795 SC_PARRYING,
5796 SC_SPEARQUICKEN,
5797 SC_ADRENALINE,
5798 SC_ADRENALINE2,
5799 SC_DANCING,
5800 SC_GS_GATLINGFEVER,
5801#ifdef RENEWAL
5802 SC_LKCONCENTRATION,
5803 SC_EDP,
5804#endif
5805 SC_FEARBREEZE,
5806 SC_EXEEDBREAK,
5807 };
5808 const enum sc_type scs_list[] = {
5809 SC_AUTOGUARD,
5810 SC_DEFENDER,
5811 SC_REFLECTSHIELD,
5812 SC_LG_REFLECTDAMAGE
5813 };
5814 int i;
5815 nullpo_ret(sd);
5816
5817 if(!sd->sc.count)
5818 return 0;
5819
5820 for (i = 0; i < ARRAYLENGTH(scw_list); i++) {
5821 // Skills requiring specific weapon types
5822 if( scw_list[i] == SC_DANCING && !battle_config.dancing_weaponswitch_fix )
5823 continue;
5824 if( sd->sc.data[scw_list[i]]
5825 && !pc_check_weapontype(sd,skill->get_weapontype(status->sc2skill(scw_list[i]))))
5826 status_change_end(&sd->bl, scw_list[i], INVALID_TIMER);
5827 }
5828
5829 if(sd->sc.data[SC_STRUP] && sd->status.weapon)
5830 // Spurt requires bare hands (feet, in fact xD)
5831 status_change_end(&sd->bl, SC_STRUP, INVALID_TIMER);
5832
5833 if(sd->status.shield <= 0) { // Skills requiring a shield
5834 for (i = 0; i < ARRAYLENGTH(scs_list); i++)
5835 if(sd->sc.data[scs_list[i]])
5836 status_change_end(&sd->bl, scs_list[i], INVALID_TIMER);
5837 }
5838 return 0;
5839}
5840
5841/*==========================================
5842 * Return equiped itemid? on player sd at pos
5843 * Return
5844 * -1 : mean nothing equiped
5845 * idx : (this index could be used in inventory to found item_data)
5846 *------------------------------------------*/
5847int pc_checkequip(struct map_session_data *sd,int pos)
5848{
5849 int i;
5850
5851 nullpo_retr(-1, sd);
5852
5853 for(i=0;i<EQI_MAX;i++){
5854 if(pos & pc->equip_pos[i])
5855 return sd->equip_index[i];
5856 }
5857
5858 return -1;
5859}
5860
5861/*==========================================
5862 * Convert's from the client's lame Job ID system
5863 * to the map server's 'makes sense' system. [Skotlex]
5864 *------------------------------------------*/
5865int pc_jobid2mapid(unsigned short b_class)
5866{
5867 switch(b_class)
5868 {
5869 //Novice And 1-1 Jobs
5870 case JOB_NOVICE: return MAPID_NOVICE;
5871 case JOB_SWORDMAN: return MAPID_SWORDMAN;
5872 case JOB_MAGE: return MAPID_MAGE;
5873 case JOB_ARCHER: return MAPID_ARCHER;
5874 case JOB_ACOLYTE: return MAPID_ACOLYTE;
5875 case JOB_MERCHANT: return MAPID_MERCHANT;
5876 case JOB_THIEF: return MAPID_THIEF;
5877 case JOB_TAEKWON: return MAPID_TAEKWON;
5878 case JOB_WEDDING: return MAPID_WEDDING;
5879 case JOB_GUNSLINGER: return MAPID_GUNSLINGER;
5880 case JOB_NINJA: return MAPID_NINJA;
5881 case JOB_XMAS: return MAPID_XMAS;
5882 case JOB_SUMMER: return MAPID_SUMMER;
5883 case JOB_GANGSI: return MAPID_GANGSI;
5884 //2-1 Jobs
5885 case JOB_SUPER_NOVICE: return MAPID_SUPER_NOVICE;
5886 case JOB_KNIGHT: return MAPID_KNIGHT;
5887 case JOB_WIZARD: return MAPID_WIZARD;
5888 case JOB_HUNTER: return MAPID_HUNTER;
5889 case JOB_PRIEST: return MAPID_PRIEST;
5890 case JOB_BLACKSMITH: return MAPID_BLACKSMITH;
5891 case JOB_ASSASSIN: return MAPID_ASSASSIN;
5892 case JOB_STAR_GLADIATOR: return MAPID_STAR_GLADIATOR;
5893 case JOB_KAGEROU:
5894 case JOB_OBORO: return MAPID_KAGEROUOBORO;
5895 case JOB_REBELLION: return MAPID_REBELLION;
5896 case JOB_DEATH_KNIGHT: return MAPID_DEATH_KNIGHT;
5897 //2-2 Jobs
5898 case JOB_CRUSADER: return MAPID_CRUSADER;
5899 case JOB_SAGE: return MAPID_SAGE;
5900 case JOB_BARD:
5901 case JOB_DANCER: return MAPID_BARDDANCER;
5902 case JOB_MONK: return MAPID_MONK;
5903 case JOB_ALCHEMIST: return MAPID_ALCHEMIST;
5904 case JOB_ROGUE: return MAPID_ROGUE;
5905 case JOB_SOUL_LINKER: return MAPID_SOUL_LINKER;
5906 case JOB_DARK_COLLECTOR: return MAPID_DARK_COLLECTOR;
5907 //Trans Novice And Trans 1-1 Jobs
5908 case JOB_NOVICE_HIGH: return MAPID_NOVICE_HIGH;
5909 case JOB_SWORDMAN_HIGH: return MAPID_SWORDMAN_HIGH;
5910 case JOB_MAGE_HIGH: return MAPID_MAGE_HIGH;
5911 case JOB_ARCHER_HIGH: return MAPID_ARCHER_HIGH;
5912 case JOB_ACOLYTE_HIGH: return MAPID_ACOLYTE_HIGH;
5913 case JOB_MERCHANT_HIGH: return MAPID_MERCHANT_HIGH;
5914 case JOB_THIEF_HIGH: return MAPID_THIEF_HIGH;
5915 //Trans 2-1 Jobs
5916 case JOB_LORD_KNIGHT: return MAPID_LORD_KNIGHT;
5917 case JOB_HIGH_WIZARD: return MAPID_HIGH_WIZARD;
5918 case JOB_SNIPER: return MAPID_SNIPER;
5919 case JOB_HIGH_PRIEST: return MAPID_HIGH_PRIEST;
5920 case JOB_WHITESMITH: return MAPID_WHITESMITH;
5921 case JOB_ASSASSIN_CROSS: return MAPID_ASSASSIN_CROSS;
5922 //Trans 2-2 Jobs
5923 case JOB_PALADIN: return MAPID_PALADIN;
5924 case JOB_PROFESSOR: return MAPID_PROFESSOR;
5925 case JOB_CLOWN:
5926 case JOB_GYPSY: return MAPID_CLOWNGYPSY;
5927 case JOB_CHAMPION: return MAPID_CHAMPION;
5928 case JOB_CREATOR: return MAPID_CREATOR;
5929 case JOB_STALKER: return MAPID_STALKER;
5930 //Baby Novice And Baby 1-1 Jobs
5931 case JOB_BABY: return MAPID_BABY;
5932 case JOB_BABY_SWORDMAN: return MAPID_BABY_SWORDMAN;
5933 case JOB_BABY_MAGE: return MAPID_BABY_MAGE;
5934 case JOB_BABY_ARCHER: return MAPID_BABY_ARCHER;
5935 case JOB_BABY_ACOLYTE: return MAPID_BABY_ACOLYTE;
5936 case JOB_BABY_MERCHANT: return MAPID_BABY_MERCHANT;
5937 case JOB_BABY_THIEF: return MAPID_BABY_THIEF;
5938 //Baby 2-1 Jobs
5939 case JOB_SUPER_BABY: return MAPID_SUPER_BABY;
5940 case JOB_BABY_KNIGHT: return MAPID_BABY_KNIGHT;
5941 case JOB_BABY_WIZARD: return MAPID_BABY_WIZARD;
5942 case JOB_BABY_HUNTER: return MAPID_BABY_HUNTER;
5943 case JOB_BABY_PRIEST: return MAPID_BABY_PRIEST;
5944 case JOB_BABY_BLACKSMITH: return MAPID_BABY_BLACKSMITH;
5945 case JOB_BABY_ASSASSIN: return MAPID_BABY_ASSASSIN;
5946 //Baby 2-2 Jobs
5947 case JOB_BABY_CRUSADER: return MAPID_BABY_CRUSADER;
5948 case JOB_BABY_SAGE: return MAPID_BABY_SAGE;
5949 case JOB_BABY_BARD:
5950 case JOB_BABY_DANCER: return MAPID_BABY_BARDDANCER;
5951 case JOB_BABY_MONK: return MAPID_BABY_MONK;
5952 case JOB_BABY_ALCHEMIST: return MAPID_BABY_ALCHEMIST;
5953 case JOB_BABY_ROGUE: return MAPID_BABY_ROGUE;
5954 //3-1 Jobs
5955 case JOB_SUPER_NOVICE_E: return MAPID_SUPER_NOVICE_E;
5956 case JOB_RUNE_KNIGHT: return MAPID_RUNE_KNIGHT;
5957 case JOB_WARLOCK: return MAPID_WARLOCK;
5958 case JOB_RANGER: return MAPID_RANGER;
5959 case JOB_ARCH_BISHOP: return MAPID_ARCH_BISHOP;
5960 case JOB_MECHANIC: return MAPID_MECHANIC;
5961 case JOB_GUILLOTINE_CROSS: return MAPID_GUILLOTINE_CROSS;
5962 //3-2 Jobs
5963 case JOB_ROYAL_GUARD: return MAPID_ROYAL_GUARD;
5964 case JOB_SORCERER: return MAPID_SORCERER;
5965 case JOB_MINSTREL:
5966 case JOB_WANDERER: return MAPID_MINSTRELWANDERER;
5967 case JOB_SURA: return MAPID_SURA;
5968 case JOB_GENETIC: return MAPID_GENETIC;
5969 case JOB_SHADOW_CHASER: return MAPID_SHADOW_CHASER;
5970 //Trans 3-1 Jobs
5971 case JOB_RUNE_KNIGHT_T: return MAPID_RUNE_KNIGHT_T;
5972 case JOB_WARLOCK_T: return MAPID_WARLOCK_T;
5973 case JOB_RANGER_T: return MAPID_RANGER_T;
5974 case JOB_ARCH_BISHOP_T: return MAPID_ARCH_BISHOP_T;
5975 case JOB_MECHANIC_T: return MAPID_MECHANIC_T;
5976 case JOB_GUILLOTINE_CROSS_T: return MAPID_GUILLOTINE_CROSS_T;
5977 //Trans 3-2 Jobs
5978 case JOB_ROYAL_GUARD_T: return MAPID_ROYAL_GUARD_T;
5979 case JOB_SORCERER_T: return MAPID_SORCERER_T;
5980 case JOB_MINSTREL_T:
5981 case JOB_WANDERER_T: return MAPID_MINSTRELWANDERER_T;
5982 case JOB_SURA_T: return MAPID_SURA_T;
5983 case JOB_GENETIC_T: return MAPID_GENETIC_T;
5984 case JOB_SHADOW_CHASER_T: return MAPID_SHADOW_CHASER_T;
5985 //Baby 3-1 Jobs
5986 case JOB_SUPER_BABY_E: return MAPID_SUPER_BABY_E;
5987 case JOB_BABY_RUNE: return MAPID_BABY_RUNE;
5988 case JOB_BABY_WARLOCK: return MAPID_BABY_WARLOCK;
5989 case JOB_BABY_RANGER: return MAPID_BABY_RANGER;
5990 case JOB_BABY_BISHOP: return MAPID_BABY_BISHOP;
5991 case JOB_BABY_MECHANIC: return MAPID_BABY_MECHANIC;
5992 case JOB_BABY_CROSS: return MAPID_BABY_CROSS;
5993 //Baby 3-2 Jobs
5994 case JOB_BABY_GUARD: return MAPID_BABY_GUARD;
5995 case JOB_BABY_SORCERER: return MAPID_BABY_SORCERER;
5996 case JOB_BABY_MINSTREL:
5997 case JOB_BABY_WANDERER: return MAPID_BABY_MINSTRELWANDERER;
5998 case JOB_BABY_SURA: return MAPID_BABY_SURA;
5999 case JOB_BABY_GENETIC: return MAPID_BABY_GENETIC;
6000 case JOB_BABY_CHASER: return MAPID_BABY_CHASER;
6001 default:
6002 return -1;
6003 }
6004}
6005
6006//Reverts the map-style class id to the client-style one.
6007int pc_mapid2jobid(unsigned short class_, int sex)
6008{
6009 switch(class_)
6010 {
6011 //Novice And 1-1 Jobs
6012 case MAPID_NOVICE: return JOB_NOVICE;
6013 case MAPID_SWORDMAN: return JOB_SWORDMAN;
6014 case MAPID_MAGE: return JOB_MAGE;
6015 case MAPID_ARCHER: return JOB_ARCHER;
6016 case MAPID_ACOLYTE: return JOB_ACOLYTE;
6017 case MAPID_MERCHANT: return JOB_MERCHANT;
6018 case MAPID_THIEF: return JOB_THIEF;
6019 case MAPID_TAEKWON: return JOB_TAEKWON;
6020 case MAPID_WEDDING: return JOB_WEDDING;
6021 case MAPID_GUNSLINGER: return JOB_GUNSLINGER;
6022 case MAPID_NINJA: return JOB_NINJA;
6023 case MAPID_XMAS: return JOB_XMAS;
6024 case MAPID_SUMMER: return JOB_SUMMER;
6025 case MAPID_GANGSI: return JOB_GANGSI;
6026 //2-1 Jobs
6027 case MAPID_SUPER_NOVICE: return JOB_SUPER_NOVICE;
6028 case MAPID_KNIGHT: return JOB_KNIGHT;
6029 case MAPID_WIZARD: return JOB_WIZARD;
6030 case MAPID_HUNTER: return JOB_HUNTER;
6031 case MAPID_PRIEST: return JOB_PRIEST;
6032 case MAPID_BLACKSMITH: return JOB_BLACKSMITH;
6033 case MAPID_ASSASSIN: return JOB_ASSASSIN;
6034 case MAPID_STAR_GLADIATOR: return JOB_STAR_GLADIATOR;
6035 case MAPID_KAGEROUOBORO: return sex?JOB_KAGEROU:JOB_OBORO;
6036 case MAPID_REBELLION: return JOB_REBELLION;
6037 case MAPID_DEATH_KNIGHT: return JOB_DEATH_KNIGHT;
6038 //2-2 Jobs
6039 case MAPID_CRUSADER: return JOB_CRUSADER;
6040 case MAPID_SAGE: return JOB_SAGE;
6041 case MAPID_BARDDANCER: return sex?JOB_BARD:JOB_DANCER;
6042 case MAPID_MONK: return JOB_MONK;
6043 case MAPID_ALCHEMIST: return JOB_ALCHEMIST;
6044 case MAPID_ROGUE: return JOB_ROGUE;
6045 case MAPID_SOUL_LINKER: return JOB_SOUL_LINKER;
6046 case MAPID_DARK_COLLECTOR: return JOB_DARK_COLLECTOR;
6047 //Trans Novice And Trans 2-1 Jobs
6048 case MAPID_NOVICE_HIGH: return JOB_NOVICE_HIGH;
6049 case MAPID_SWORDMAN_HIGH: return JOB_SWORDMAN_HIGH;
6050 case MAPID_MAGE_HIGH: return JOB_MAGE_HIGH;
6051 case MAPID_ARCHER_HIGH: return JOB_ARCHER_HIGH;
6052 case MAPID_ACOLYTE_HIGH: return JOB_ACOLYTE_HIGH;
6053 case MAPID_MERCHANT_HIGH: return JOB_MERCHANT_HIGH;
6054 case MAPID_THIEF_HIGH: return JOB_THIEF_HIGH;
6055 //Trans 2-1 Jobs
6056 case MAPID_LORD_KNIGHT: return JOB_LORD_KNIGHT;
6057 case MAPID_HIGH_WIZARD: return JOB_HIGH_WIZARD;
6058 case MAPID_SNIPER: return JOB_SNIPER;
6059 case MAPID_HIGH_PRIEST: return JOB_HIGH_PRIEST;
6060 case MAPID_WHITESMITH: return JOB_WHITESMITH;
6061 case MAPID_ASSASSIN_CROSS: return JOB_ASSASSIN_CROSS;
6062 //Trans 2-2 Jobs
6063 case MAPID_PALADIN: return JOB_PALADIN;
6064 case MAPID_PROFESSOR: return JOB_PROFESSOR;
6065 case MAPID_CLOWNGYPSY: return sex?JOB_CLOWN:JOB_GYPSY;
6066 case MAPID_CHAMPION: return JOB_CHAMPION;
6067 case MAPID_CREATOR: return JOB_CREATOR;
6068 case MAPID_STALKER: return JOB_STALKER;
6069 //Baby Novice And Baby 1-1 Jobs
6070 case MAPID_BABY: return JOB_BABY;
6071 case MAPID_BABY_SWORDMAN: return JOB_BABY_SWORDMAN;
6072 case MAPID_BABY_MAGE: return JOB_BABY_MAGE;
6073 case MAPID_BABY_ARCHER: return JOB_BABY_ARCHER;
6074 case MAPID_BABY_ACOLYTE: return JOB_BABY_ACOLYTE;
6075 case MAPID_BABY_MERCHANT: return JOB_BABY_MERCHANT;
6076 case MAPID_BABY_THIEF: return JOB_BABY_THIEF;
6077 //Baby 2-1 Jobs
6078 case MAPID_SUPER_BABY: return JOB_SUPER_BABY;
6079 case MAPID_BABY_KNIGHT: return JOB_BABY_KNIGHT;
6080 case MAPID_BABY_WIZARD: return JOB_BABY_WIZARD;
6081 case MAPID_BABY_HUNTER: return JOB_BABY_HUNTER;
6082 case MAPID_BABY_PRIEST: return JOB_BABY_PRIEST;
6083 case MAPID_BABY_BLACKSMITH: return JOB_BABY_BLACKSMITH;
6084 case MAPID_BABY_ASSASSIN: return JOB_BABY_ASSASSIN;
6085 //Baby 2-2 Jobs
6086 case MAPID_BABY_CRUSADER: return JOB_BABY_CRUSADER;
6087 case MAPID_BABY_SAGE: return JOB_BABY_SAGE;
6088 case MAPID_BABY_BARDDANCER: return sex?JOB_BABY_BARD:JOB_BABY_DANCER;
6089 case MAPID_BABY_MONK: return JOB_BABY_MONK;
6090 case MAPID_BABY_ALCHEMIST: return JOB_BABY_ALCHEMIST;
6091 case MAPID_BABY_ROGUE: return JOB_BABY_ROGUE;
6092 //3-1 Jobs
6093 case MAPID_SUPER_NOVICE_E: return JOB_SUPER_NOVICE_E;
6094 case MAPID_RUNE_KNIGHT: return JOB_RUNE_KNIGHT;
6095 case MAPID_WARLOCK: return JOB_WARLOCK;
6096 case MAPID_RANGER: return JOB_RANGER;
6097 case MAPID_ARCH_BISHOP: return JOB_ARCH_BISHOP;
6098 case MAPID_MECHANIC: return JOB_MECHANIC;
6099 case MAPID_GUILLOTINE_CROSS: return JOB_GUILLOTINE_CROSS;
6100 //3-2 Jobs
6101 case MAPID_ROYAL_GUARD: return JOB_ROYAL_GUARD;
6102 case MAPID_SORCERER: return JOB_SORCERER;
6103 case MAPID_MINSTRELWANDERER: return sex?JOB_MINSTREL:JOB_WANDERER;
6104 case MAPID_SURA: return JOB_SURA;
6105 case MAPID_GENETIC: return JOB_GENETIC;
6106 case MAPID_SHADOW_CHASER: return JOB_SHADOW_CHASER;
6107 //Trans 3-1 Jobs
6108 case MAPID_RUNE_KNIGHT_T: return JOB_RUNE_KNIGHT_T;
6109 case MAPID_WARLOCK_T: return JOB_WARLOCK_T;
6110 case MAPID_RANGER_T: return JOB_RANGER_T;
6111 case MAPID_ARCH_BISHOP_T: return JOB_ARCH_BISHOP_T;
6112 case MAPID_MECHANIC_T: return JOB_MECHANIC_T;
6113 case MAPID_GUILLOTINE_CROSS_T: return JOB_GUILLOTINE_CROSS_T;
6114 //Trans 3-2 Jobs
6115 case MAPID_ROYAL_GUARD_T: return JOB_ROYAL_GUARD_T;
6116 case MAPID_SORCERER_T: return JOB_SORCERER_T;
6117 case MAPID_MINSTRELWANDERER_T: return sex?JOB_MINSTREL_T:JOB_WANDERER_T;
6118 case MAPID_SURA_T: return JOB_SURA_T;
6119 case MAPID_GENETIC_T: return JOB_GENETIC_T;
6120 case MAPID_SHADOW_CHASER_T: return JOB_SHADOW_CHASER_T;
6121 //Baby 3-1 Jobs
6122 case MAPID_SUPER_BABY_E: return JOB_SUPER_BABY_E;
6123 case MAPID_BABY_RUNE: return JOB_BABY_RUNE;
6124 case MAPID_BABY_WARLOCK: return JOB_BABY_WARLOCK;
6125 case MAPID_BABY_RANGER: return JOB_BABY_RANGER;
6126 case MAPID_BABY_BISHOP: return JOB_BABY_BISHOP;
6127 case MAPID_BABY_MECHANIC: return JOB_BABY_MECHANIC;
6128 case MAPID_BABY_CROSS: return JOB_BABY_CROSS;
6129 //Baby 3-2 Jobs
6130 case MAPID_BABY_GUARD: return JOB_BABY_GUARD;
6131 case MAPID_BABY_SORCERER: return JOB_BABY_SORCERER;
6132 case MAPID_BABY_MINSTRELWANDERER: return sex?JOB_BABY_MINSTREL:JOB_BABY_WANDERER;
6133 case MAPID_BABY_SURA: return JOB_BABY_SURA;
6134 case MAPID_BABY_GENETIC: return JOB_BABY_GENETIC;
6135 case MAPID_BABY_CHASER: return JOB_BABY_CHASER;
6136 default:
6137 return -1;
6138 }
6139}
6140
6141/*====================================================
6142 * This function return the name of the job (by [Yor])
6143 *----------------------------------------------------*/
6144const char* job_name(int class_)
6145{
6146 switch (class_) {
6147 case JOB_NOVICE: // 550
6148 case JOB_SWORDMAN: // 551
6149 case JOB_MAGE: // 552
6150 case JOB_ARCHER: // 553
6151 case JOB_ACOLYTE: // 554
6152 case JOB_MERCHANT: // 555
6153 case JOB_THIEF: // 556
6154 return msg_txt(550 - JOB_NOVICE+class_);
6155
6156 case JOB_KNIGHT: // 557
6157 case JOB_PRIEST: // 558
6158 case JOB_WIZARD: // 559
6159 case JOB_BLACKSMITH: // 560
6160 case JOB_HUNTER: // 561
6161 case JOB_ASSASSIN: // 562
6162 return msg_txt(557 - JOB_KNIGHT+class_);
6163
6164 case JOB_KNIGHT2:
6165 return msg_txt(557);
6166
6167 case JOB_CRUSADER: // 563
6168 case JOB_MONK: // 564
6169 case JOB_SAGE: // 565
6170 case JOB_ROGUE: // 566
6171 case JOB_ALCHEMIST: // 567
6172 case JOB_BARD: // 568
6173 case JOB_DANCER: // 569
6174 return msg_txt(563 - JOB_CRUSADER+class_);
6175
6176 case JOB_CRUSADER2:
6177 return msg_txt(563);
6178
6179 case JOB_WEDDING: // 570
6180 case JOB_SUPER_NOVICE: // 571
6181 case JOB_GUNSLINGER: // 572
6182 case JOB_NINJA: // 573
6183 case JOB_XMAS: // 574
6184 return msg_txt(570 - JOB_WEDDING+class_);
6185
6186 case JOB_SUMMER:
6187 return msg_txt(621);
6188
6189 case JOB_NOVICE_HIGH: // 575
6190 case JOB_SWORDMAN_HIGH: // 576
6191 case JOB_MAGE_HIGH: // 577
6192 case JOB_ARCHER_HIGH: // 578
6193 case JOB_ACOLYTE_HIGH: // 579
6194 case JOB_MERCHANT_HIGH: // 580
6195 case JOB_THIEF_HIGH: // 581
6196 return msg_txt(575 - JOB_NOVICE_HIGH+class_);
6197
6198 case JOB_LORD_KNIGHT: // 582
6199 case JOB_HIGH_PRIEST: // 583
6200 case JOB_HIGH_WIZARD: // 584
6201 case JOB_WHITESMITH: // 585
6202 case JOB_SNIPER: // 586
6203 case JOB_ASSASSIN_CROSS: // 587
6204 return msg_txt(582 - JOB_LORD_KNIGHT+class_);
6205
6206 case JOB_LORD_KNIGHT2:
6207 return msg_txt(582);
6208
6209 case JOB_PALADIN: // 588
6210 case JOB_CHAMPION: // 589
6211 case JOB_PROFESSOR: // 590
6212 case JOB_STALKER: // 591
6213 case JOB_CREATOR: // 592
6214 case JOB_CLOWN: // 593
6215 case JOB_GYPSY: // 594
6216 return msg_txt(588 - JOB_PALADIN + class_);
6217
6218 case JOB_PALADIN2:
6219 return msg_txt(588);
6220
6221 case JOB_BABY: // 595
6222 case JOB_BABY_SWORDMAN: // 596
6223 case JOB_BABY_MAGE: // 597
6224 case JOB_BABY_ARCHER: // 598
6225 case JOB_BABY_ACOLYTE: // 599
6226 case JOB_BABY_MERCHANT: // 600
6227 case JOB_BABY_THIEF: // 601
6228 return msg_txt(595 - JOB_BABY + class_);
6229
6230 case JOB_BABY_KNIGHT: // 602
6231 case JOB_BABY_PRIEST: // 603
6232 case JOB_BABY_WIZARD: // 604
6233 case JOB_BABY_BLACKSMITH: // 605
6234 case JOB_BABY_HUNTER: // 606
6235 case JOB_BABY_ASSASSIN: // 607
6236 return msg_txt(602 - JOB_BABY_KNIGHT + class_);
6237
6238 case JOB_BABY_KNIGHT2:
6239 return msg_txt(602);
6240
6241 case JOB_BABY_CRUSADER: // 608
6242 case JOB_BABY_MONK: // 609
6243 case JOB_BABY_SAGE: // 610
6244 case JOB_BABY_ROGUE: // 611
6245 case JOB_BABY_ALCHEMIST: // 612
6246 case JOB_BABY_BARD: // 613
6247 case JOB_BABY_DANCER: // 614
6248 return msg_txt(608 - JOB_BABY_CRUSADER + class_);
6249
6250 case JOB_BABY_CRUSADER2:
6251 return msg_txt(608);
6252
6253 case JOB_SUPER_BABY:
6254 return msg_txt(615);
6255
6256 case JOB_TAEKWON:
6257 return msg_txt(616);
6258 case JOB_STAR_GLADIATOR:
6259 case JOB_STAR_GLADIATOR2:
6260 return msg_txt(617);
6261 case JOB_SOUL_LINKER:
6262 return msg_txt(618);
6263
6264 case JOB_GANGSI: // 622
6265 case JOB_DEATH_KNIGHT: // 623
6266 case JOB_DARK_COLLECTOR: // 624
6267 return msg_txt(622 - JOB_GANGSI+class_);
6268
6269 case JOB_RUNE_KNIGHT: // 625
6270 case JOB_WARLOCK: // 626
6271 case JOB_RANGER: // 627
6272 case JOB_ARCH_BISHOP: // 628
6273 case JOB_MECHANIC: // 629
6274 case JOB_GUILLOTINE_CROSS: // 630
6275 return msg_txt(625 - JOB_RUNE_KNIGHT+class_);
6276
6277 case JOB_RUNE_KNIGHT_T: // 656
6278 case JOB_WARLOCK_T: // 657
6279 case JOB_RANGER_T: // 658
6280 case JOB_ARCH_BISHOP_T: // 659
6281 case JOB_MECHANIC_T: // 660
6282 case JOB_GUILLOTINE_CROSS_T: // 661
6283 return msg_txt(656 - JOB_RUNE_KNIGHT_T+class_);
6284
6285 case JOB_ROYAL_GUARD: // 631
6286 case JOB_SORCERER: // 632
6287 case JOB_MINSTREL: // 633
6288 case JOB_WANDERER: // 634
6289 case JOB_SURA: // 635
6290 case JOB_GENETIC: // 636
6291 case JOB_SHADOW_CHASER: // 637
6292 return msg_txt(631 - JOB_ROYAL_GUARD+class_);
6293
6294 case JOB_ROYAL_GUARD_T: // 662
6295 case JOB_SORCERER_T: // 663
6296 case JOB_MINSTREL_T: // 664
6297 case JOB_WANDERER_T: // 665
6298 case JOB_SURA_T: // 666
6299 case JOB_GENETIC_T: // 667
6300 case JOB_SHADOW_CHASER_T: // 668
6301 return msg_txt(662 - JOB_ROYAL_GUARD_T+class_);
6302
6303 case JOB_RUNE_KNIGHT2:
6304 return msg_txt(625);
6305
6306 case JOB_RUNE_KNIGHT_T2:
6307 return msg_txt(656);
6308
6309 case JOB_ROYAL_GUARD2:
6310 return msg_txt(631);
6311
6312 case JOB_ROYAL_GUARD_T2:
6313 return msg_txt(662);
6314
6315 case JOB_RANGER2:
6316 return msg_txt(627);
6317
6318 case JOB_RANGER_T2:
6319 return msg_txt(658);
6320
6321 case JOB_MECHANIC2:
6322 return msg_txt(629);
6323
6324 case JOB_MECHANIC_T2:
6325 return msg_txt(660);
6326
6327 case JOB_BABY_RUNE: // 638
6328 case JOB_BABY_WARLOCK: // 639
6329 case JOB_BABY_RANGER: // 640
6330 case JOB_BABY_BISHOP: // 641
6331 case JOB_BABY_MECHANIC: // 642
6332 case JOB_BABY_CROSS: // 643
6333 case JOB_BABY_GUARD: // 644
6334 case JOB_BABY_SORCERER: // 645
6335 case JOB_BABY_MINSTREL: // 646
6336 case JOB_BABY_WANDERER: // 647
6337 case JOB_BABY_SURA: // 648
6338 case JOB_BABY_GENETIC: // 649
6339 case JOB_BABY_CHASER: // 650
6340 return msg_txt(638 - JOB_BABY_RUNE+class_);
6341
6342 case JOB_BABY_RUNE2:
6343 return msg_txt(638);
6344
6345 case JOB_BABY_GUARD2:
6346 return msg_txt(644);
6347
6348 case JOB_BABY_RANGER2:
6349 return msg_txt(640);
6350
6351 case JOB_BABY_MECHANIC2:
6352 return msg_txt(642);
6353
6354 case JOB_SUPER_NOVICE_E: // 651
6355 case JOB_SUPER_BABY_E: // 652
6356 return msg_txt(651 - JOB_SUPER_NOVICE_E+class_);
6357
6358 case JOB_KAGEROU: // 653
6359 case JOB_OBORO: // 654
6360 return msg_txt(653 - JOB_KAGEROU+class_);
6361
6362 case JOB_REBELLION:
6363 return msg_txt(655);
6364
6365 default:
6366 return msg_txt(620); // "Unknown Job"
6367 }
6368}
6369
6370int pc_check_job_name(const char *name) {
6371 int i, len;
6372 struct {
6373 const char *name;
6374 int id;
6375 } names[] = {
6376 { "Novice", JOB_NOVICE },
6377 { "Swordsman", JOB_SWORDMAN },
6378 { "Magician", JOB_MAGE },
6379 { "Archer", JOB_ARCHER },
6380 { "Acolyte", JOB_ACOLYTE },
6381 { "Merchant", JOB_MERCHANT },
6382 { "Thief", JOB_THIEF },
6383 { "Knight", JOB_KNIGHT },
6384 { "Priest", JOB_PRIEST },
6385 { "Wizard", JOB_WIZARD },
6386 { "Blacksmith", JOB_BLACKSMITH },
6387 { "Hunter", JOB_HUNTER },
6388 { "Assassin", JOB_ASSASSIN },
6389 { "Crusader", JOB_CRUSADER },
6390 { "Monk", JOB_MONK },
6391 { "Sage", JOB_SAGE },
6392 { "Rogue", JOB_ROGUE },
6393 { "Alchemist", JOB_ALCHEMIST },
6394 { "Bard", JOB_BARD },
6395 { "Dancer", JOB_DANCER },
6396 { "Super_Novice", JOB_SUPER_NOVICE },
6397 { "Gunslinger", JOB_GUNSLINGER },
6398 { "Ninja", JOB_NINJA },
6399 { "Novice_High", JOB_NOVICE_HIGH },
6400 { "Swordsman_High", JOB_SWORDMAN_HIGH },
6401 { "Magician_High", JOB_MAGE_HIGH },
6402 { "Archer_High", JOB_ARCHER_HIGH },
6403 { "Acolyte_High", JOB_ACOLYTE_HIGH },
6404 { "Merchant_High", JOB_MERCHANT_HIGH },
6405 { "Thief_High", JOB_THIEF_HIGH },
6406 { "Lord_Knight", JOB_LORD_KNIGHT },
6407 { "High_Priest", JOB_HIGH_PRIEST },
6408 { "High_Wizard", JOB_HIGH_WIZARD },
6409 { "Whitesmith", JOB_WHITESMITH },
6410 { "Sniper", JOB_SNIPER },
6411 { "Assassin_Cross", JOB_ASSASSIN_CROSS },
6412 { "Paladin", JOB_PALADIN },
6413 { "Champion", JOB_CHAMPION },
6414 { "Professor", JOB_PROFESSOR },
6415 { "Stalker", JOB_STALKER },
6416 { "Creator", JOB_CREATOR },
6417 { "Clown", JOB_CLOWN },
6418 { "Gypsy", JOB_GYPSY },
6419 { "Baby_Novice", JOB_BABY },
6420 { "Baby_Swordsman", JOB_BABY_SWORDMAN },
6421 { "Baby_Magician", JOB_BABY_MAGE },
6422 { "Baby_Archer", JOB_BABY_ARCHER },
6423 { "Baby_Acolyte", JOB_BABY_ACOLYTE },
6424 { "Baby_Merchant", JOB_BABY_MERCHANT },
6425 { "Baby_Thief", JOB_BABY_THIEF },
6426 { "Baby_Knight", JOB_BABY_KNIGHT },
6427 { "Baby_Priest", JOB_BABY_PRIEST },
6428 { "Baby_Wizard", JOB_BABY_WIZARD },
6429 { "Baby_Blacksmith", JOB_BABY_BLACKSMITH },
6430 { "Baby_Hunter", JOB_BABY_HUNTER },
6431 { "Baby_Assassin", JOB_BABY_ASSASSIN },
6432 { "Baby_Crusader", JOB_BABY_CRUSADER },
6433 { "Baby_Monk", JOB_BABY_MONK },
6434 { "Baby_Sage", JOB_BABY_SAGE },
6435 { "Baby_Rogue", JOB_BABY_ROGUE },
6436 { "Baby_Alchemist", JOB_BABY_ALCHEMIST },
6437 { "Baby_Bard", JOB_BABY_BARD },
6438 { "Baby_Dancer", JOB_BABY_DANCER },
6439 { "Super_Baby", JOB_SUPER_BABY },
6440 { "Taekwon", JOB_TAEKWON },
6441 { "Star_Gladiator", JOB_STAR_GLADIATOR },
6442 { "Soul_Linker", JOB_SOUL_LINKER },
6443 { "Gangsi", JOB_GANGSI },
6444 { "Death_Knight", JOB_DEATH_KNIGHT },
6445 { "Dark_Collector", JOB_DARK_COLLECTOR },
6446 { "Rune_Knight", JOB_RUNE_KNIGHT },
6447 { "Warlock", JOB_WARLOCK },
6448 { "Ranger", JOB_RANGER },
6449 { "Arch_Bishop", JOB_ARCH_BISHOP },
6450 { "Mechanic", JOB_MECHANIC },
6451 { "Guillotine_Cross", JOB_GUILLOTINE_CROSS },
6452 { "Rune_Knight_Trans", JOB_RUNE_KNIGHT_T },
6453 { "Warlock_Trans", JOB_WARLOCK_T },
6454 { "Ranger_Trans", JOB_RANGER_T },
6455 { "Arch_Bishop_Trans", JOB_ARCH_BISHOP_T },
6456 { "Mechanic_Trans", JOB_MECHANIC_T },
6457 { "Guillotine_Cross_Trans", JOB_GUILLOTINE_CROSS_T },
6458 { "Royal_Guard", JOB_ROYAL_GUARD },
6459 { "Sorcerer", JOB_SORCERER },
6460 { "Minstrel", JOB_MINSTREL },
6461 { "Wanderer", JOB_WANDERER },
6462 { "Sura", JOB_SURA },
6463 { "Genetic", JOB_GENETIC },
6464 { "Shadow_Chaser", JOB_SHADOW_CHASER },
6465 { "Royal_Guard_Trans", JOB_ROYAL_GUARD_T },
6466 { "Sorcerer_Trans", JOB_SORCERER_T },
6467 { "Minstrel_Trans", JOB_MINSTREL_T },
6468 { "Wanderer_Trans", JOB_WANDERER_T },
6469 { "Sura_Trans", JOB_SURA_T },
6470 { "Genetic_Trans", JOB_GENETIC_T },
6471 { "Shadow_Chaser_Trans", JOB_SHADOW_CHASER_T },
6472 { "Baby_Rune_Knight", JOB_BABY_RUNE },
6473 { "Baby_Warlock", JOB_BABY_WARLOCK },
6474 { "Baby_Ranger", JOB_BABY_RANGER },
6475 { "Baby_Arch_Bishop", JOB_BABY_BISHOP },
6476 { "Baby_Mechanic", JOB_BABY_MECHANIC },
6477 { "Baby_Guillotine_Cross", JOB_BABY_CROSS },
6478 { "Baby_Royal_Guard", JOB_BABY_GUARD },
6479 { "Baby_Sorcerer", JOB_BABY_SORCERER },
6480 { "Baby_Minstrel", JOB_BABY_MINSTREL },
6481 { "Baby_Wanderer", JOB_BABY_WANDERER },
6482 { "Baby_Sura", JOB_BABY_SURA },
6483 { "Baby_Genetic", JOB_BABY_GENETIC },
6484 { "Baby_Shadow_Chaser", JOB_BABY_CHASER },
6485 { "Expanded_Super_Novice", JOB_SUPER_NOVICE_E },
6486 { "Expanded_Super_Baby", JOB_SUPER_BABY_E },
6487 { "Kagerou", JOB_KAGEROU },
6488 { "Oboro", JOB_OBORO },
6489 { "Rebellion", JOB_REBELLION },
6490 };
6491
6492 nullpo_retr(-1, name);
6493 len = ARRAYLENGTH(names);
6494
6495 ARR_FIND(0, len, i, strcmpi(names[i].name, name) == 0);
6496
6497 if ( i == len )
6498 return -1;
6499
6500 return names[i].id;
6501}
6502
6503int pc_follow_timer(int tid, int64 tick, int id, intptr_t data) {
6504 struct map_session_data *sd;
6505 struct block_list *tbl;
6506
6507 sd = map->id2sd(id);
6508 nullpo_ret(sd);
6509
6510 if (sd->followtimer != tid) {
6511 ShowError("pc_follow_timer %d != %d\n",sd->followtimer,tid);
6512 sd->followtimer = INVALID_TIMER;
6513 return 0;
6514 }
6515
6516 sd->followtimer = INVALID_TIMER;
6517 tbl = map->id2bl(sd->followtarget);
6518
6519 if (tbl == NULL || pc_isdead(sd) || status->isdead(tbl)) {
6520 pc->stop_following(sd);
6521 return 0;
6522 }
6523
6524 // either player or target is currently detached from map blocks (could be teleporting),
6525 // but still connected to this map, so we'll just increment the timer and check back later
6526 if (sd->bl.prev != NULL && tbl->prev != NULL
6527 && sd->ud.skilltimer == INVALID_TIMER && sd->ud.attacktimer == INVALID_TIMER && sd->ud.walktimer == INVALID_TIMER
6528 ) {
6529 if((sd->bl.m == tbl->m) && unit->can_reach_bl(&sd->bl,tbl, AREA_SIZE, 0, NULL, NULL)) {
6530 if (!check_distance_bl(&sd->bl, tbl, 5))
6531 unit->walktobl(&sd->bl, tbl, 5, 0);
6532 } else
6533 pc->setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT);
6534 }
6535 sd->followtimer = timer->add(
6536 tick + 1000, // increase time a bit to loosen up map's load
6537 pc->follow_timer, sd->bl.id, 0);
6538 return 0;
6539}
6540
6541int pc_stop_following (struct map_session_data *sd)
6542{
6543 nullpo_ret(sd);
6544
6545 if (sd->followtimer != INVALID_TIMER) {
6546 timer->delete(sd->followtimer,pc->follow_timer);
6547 sd->followtimer = INVALID_TIMER;
6548 }
6549 sd->followtarget = -1;
6550 sd->ud.target_to = 0;
6551
6552 unit->stop_walking(&sd->bl, STOPWALKING_FLAG_FIXPOS);
6553
6554 return 0;
6555}
6556
6557int pc_follow(struct map_session_data *sd,int target_id) {
6558 struct block_list *bl = map->id2bl(target_id);
6559 nullpo_retr(1, sd);
6560 if (bl == NULL /*|| bl->type != BL_PC*/)
6561 return 1;
6562 if (sd->followtimer != INVALID_TIMER)
6563 pc->stop_following(sd);
6564
6565 sd->followtarget = target_id;
6566 pc->follow_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0);
6567
6568 return 0;
6569}
6570
6571int pc_checkbaselevelup(struct map_session_data *sd) {
6572 unsigned int next = pc->nextbaseexp(sd);
6573
6574 nullpo_ret(sd);
6575 if (!next || sd->status.base_exp < next)
6576 return 0;
6577
6578 do {
6579 int status_points = 0;
6580 sd->status.base_exp -= next;
6581 //Kyoki pointed out that the max overcarry exp is the exp needed for the previous level -1. [Skotlex]
6582 if(!battle_config.multi_level_up && sd->status.base_exp > next-1)
6583 sd->status.base_exp = next-1;
6584
6585 status_points = pc->gets_status_point(sd->status.base_level);
6586 sd->status.base_level++;
6587 sd->status.status_point += status_points;
6588
6589 } while ((next=pc->nextbaseexp(sd)) > 0 && sd->status.base_exp >= next);
6590
6591 if (battle_config.pet_lv_rate && sd->pd) //<Skotlex> update pet's level
6592 status_calc_pet(sd->pd,SCO_NONE);
6593
6594 clif->updatestatus(sd,SP_STATUSPOINT);
6595 clif->updatestatus(sd,SP_BASELEVEL);
6596 clif->updatestatus(sd,SP_BASEEXP);
6597 clif->updatestatus(sd,SP_NEXTBASEEXP);
6598 status_calc_pc(sd,SCO_FORCE);
6599 status_percent_heal(&sd->bl,100,100);
6600
6601 if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) {
6602 sc_start(NULL,&sd->bl,status->skill2sc(PR_KYRIE),100,1,skill->get_time(PR_KYRIE,1));
6603 sc_start(NULL,&sd->bl,status->skill2sc(PR_IMPOSITIO),100,1,skill->get_time(PR_IMPOSITIO,1));
6604 sc_start(NULL,&sd->bl,status->skill2sc(PR_MAGNIFICAT),100,1,skill->get_time(PR_MAGNIFICAT,1));
6605 sc_start(NULL,&sd->bl,status->skill2sc(PR_GLORIA),100,1,skill->get_time(PR_GLORIA,1));
6606 sc_start(NULL,&sd->bl,status->skill2sc(PR_SUFFRAGIUM),100,1,skill->get_time(PR_SUFFRAGIUM,1));
6607 if (sd->state.snovice_dead_flag)
6608 sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead.
6609 } else if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) {
6610 sc_start(NULL,&sd->bl,status->skill2sc(AL_INCAGI),100,10,600000);
6611 sc_start(NULL,&sd->bl,status->skill2sc(AL_BLESSING),100,10,600000);
6612 }
6613 clif->misceffect(&sd->bl,0);
6614 npc->script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT
6615
6616 if(sd->status.party_id)
6617 party->send_levelup(sd);
6618
6619 pc->baselevelchanged(sd);
6620 return 1;
6621}
6622
6623void pc_baselevelchanged(struct map_session_data *sd) {
6624 int i;
6625 nullpo_retv(sd);
6626 for( i = 0; i < EQI_MAX; i++ ) {
6627 if( sd->equip_index[i] >= 0 ) {
6628 if (sd->inventory_data[sd->equip_index[i]]->elvmax != 0 && sd->status.base_level > sd->inventory_data[ sd->equip_index[i] ]->elvmax)
6629 pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
6630 }
6631 }
6632}
6633
6634int pc_checkjoblevelup(struct map_session_data *sd)
6635{
6636 unsigned int next = pc->nextjobexp(sd);
6637
6638 nullpo_ret(sd);
6639 if(!next || sd->status.job_exp < next)
6640 return 0;
6641
6642 do {
6643 sd->status.job_exp -= next;
6644 //Kyoki pointed out that the max overcarry exp is the exp needed for the previous level -1. [Skotlex]
6645 if(!battle_config.multi_level_up && sd->status.job_exp > next-1)
6646 sd->status.job_exp = next-1;
6647
6648 sd->status.job_level++;
6649 sd->status.skill_point++;
6650
6651 } while ((next=pc->nextjobexp(sd)) > 0 && sd->status.job_exp >= next);
6652
6653 clif->updatestatus(sd,SP_JOBLEVEL);
6654 clif->updatestatus(sd,SP_JOBEXP);
6655 clif->updatestatus(sd,SP_NEXTJOBEXP);
6656 clif->updatestatus(sd,SP_SKILLPOINT);
6657 status_calc_pc(sd,SCO_FORCE);
6658 clif->misceffect(&sd->bl,1);
6659 if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd))
6660 clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL.
6661
6662 npc->script_event(sd, NPCE_JOBLVUP);
6663 return 1;
6664}
6665
6666/**
6667 * Alters EXP based on self bonuses that do not get shared with the party
6668 **/
6669void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src) {
6670 int buff_ratio = 0, buff_job_ratio = 0, race_ratio = 0, pk_ratio = 0;
6671 int64 jexp, bexp;
6672
6673 nullpo_retv(sd);
6674 nullpo_retv(base_exp);
6675 nullpo_retv(job_exp);
6676
6677 jexp = *job_exp;
6678 bexp = *base_exp;
6679
6680 if (src != NULL) {
6681 const struct status_data *st = status->get_status_data(src);
6682
6683#ifdef RENEWAL_EXP //should happen first before we caluclate any modifiers
6684 if (src->type == BL_MOB) {
6685 const struct mob_data *md = BL_UCAST(BL_MOB, src);
6686 int re_mod;
6687 re_mod = pc->level_penalty_mod(md->level - sd->status.base_level, md->status.race, md->status.mode, 1);
6688 jexp = apply_percentrate64(jexp, re_mod, 100);
6689 bexp = apply_percentrate64(bexp, re_mod, 100);
6690 }
6691#endif
6692
6693 //Race modifier
6694 if (sd->expaddrace[st->race])
6695 race_ratio += sd->expaddrace[st->race];
6696 race_ratio += sd->expaddrace[(st->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS];
6697 }
6698
6699
6700 //PK modifier
6701 /* this doesn't exist in Aegis, instead there's a CrazyKiller check which double all EXP from this point */
6702 if (battle_config.pk_mode && status->get_lv(src) - sd->status.base_level >= 20)
6703 pk_ratio += 15; // pk_mode additional exp if monster >20 levels [Valaris]
6704
6705
6706 //Buffs modifier
6707 if (sd->sc.data[SC_CASH_PLUSEXP]) {
6708 buff_job_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1;
6709 buff_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1;
6710 }
6711 if (sd->sc.data[SC_OVERLAPEXPUP]) {
6712 buff_job_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1;
6713 buff_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1;
6714 }
6715 if (sd->sc.data[SC_CASH_PLUSONLYJOBEXP])
6716 buff_job_ratio += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1;
6717
6718 //Applying Race and PK modifier First then Premium (Perment modifier) and finally buff modifier
6719 jexp += apply_percentrate64(jexp, race_ratio, 100);
6720 jexp += apply_percentrate64(jexp, pk_ratio, 100);
6721
6722 bexp += apply_percentrate64(bexp, race_ratio, 100);
6723 bexp += apply_percentrate64(bexp, pk_ratio, 100);
6724
6725
6726 if (sd->status.mod_exp != 100) {
6727 jexp = apply_percentrate64(jexp, sd->status.mod_exp, 100);
6728 bexp = apply_percentrate64(bexp, sd->status.mod_exp, 100);
6729 }
6730
6731 bexp += apply_percentrate64(bexp, buff_ratio, 100);
6732 jexp += apply_percentrate64(jexp, buff_ratio + buff_job_ratio, 100);
6733
6734 *job_exp = (unsigned int)cap_value(jexp, 1, UINT_MAX);
6735 *base_exp = (unsigned int)cap_value(bexp, 1, UINT_MAX);
6736}
6737
6738/**
6739 * Gives a determined EXP amount to sd and calculates remaining EXP for next level
6740 * @param src if is NULL no bonuses are taken into account
6741 * @param is_quest Used to let client know that the EXP was from a quest (clif->displayexp) PACKETVER >= 20091027
6742 * @retval true success
6743 **/
6744bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int base_exp,unsigned int job_exp,bool is_quest) {
6745 float nextbp=0, nextjp=0;
6746 unsigned int nextb=0, nextj=0;
6747 nullpo_ret(sd);
6748
6749 if (sd->bl.prev == NULL || pc_isdead(sd))
6750 return false;
6751
6752 if (!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr]
6753 return false; // no exp on pvp maps
6754
6755 if (pc_has_permission(sd,PC_PERM_DISABLE_EXP))
6756 return false;
6757
6758 if (src)
6759 pc->calcexp(sd, &base_exp, &job_exp, src);
6760
6761 if (sd->status.guild_id > 0)
6762 base_exp -= guild->payexp(sd,base_exp);
6763
6764 nextb = pc->nextbaseexp(sd);
6765 nextj = pc->nextjobexp(sd);
6766
6767 if (sd->state.showexp || battle_config.max_exp_gain_rate) {
6768 if (nextb > 0)
6769 nextbp = (float) base_exp / (float) nextb;
6770 if (nextj > 0)
6771 nextjp = (float) job_exp / (float) nextj;
6772
6773 if(battle_config.max_exp_gain_rate) {
6774 if (nextbp > battle_config.max_exp_gain_rate/1000.) {
6775 //Note that this value should never be greater than the original
6776 //base_exp, therefore no overflow checks are needed. [Skotlex]
6777 base_exp = (unsigned int)(battle_config.max_exp_gain_rate/1000.*nextb);
6778 if (sd->state.showexp)
6779 nextbp = (float) base_exp / (float) nextb;
6780 }
6781 if (nextjp > battle_config.max_exp_gain_rate/1000.) {
6782 job_exp = (unsigned int)(battle_config.max_exp_gain_rate/1000.*nextj);
6783 if (sd->state.showexp)
6784 nextjp = (float) job_exp / (float) nextj;
6785 }
6786 }
6787 }
6788
6789 // Cap exp to the level up requirement of the previous level when you are at max level,
6790 // otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex]
6791 if (base_exp) {
6792 nextb = nextb?UINT_MAX:pc->thisbaseexp(sd);
6793 if(sd->status.base_exp > nextb - base_exp)
6794 sd->status.base_exp = nextb;
6795 else
6796 sd->status.base_exp += base_exp;
6797 pc->checkbaselevelup(sd);
6798 clif->updatestatus(sd,SP_BASEEXP);
6799 }
6800
6801 if (job_exp) {
6802 nextj = nextj?UINT_MAX:pc->thisjobexp(sd);
6803 if(sd->status.job_exp > nextj - job_exp)
6804 sd->status.job_exp = nextj;
6805 else
6806 sd->status.job_exp += job_exp;
6807 pc->checkjoblevelup(sd);
6808 clif->updatestatus(sd,SP_JOBEXP);
6809 }
6810
6811#if PACKETVER >= 20091027
6812 if(base_exp)
6813 clif->displayexp(sd, base_exp, SP_BASEEXP, is_quest);
6814 if(job_exp)
6815 clif->displayexp(sd, job_exp, SP_JOBEXP, is_quest);
6816#endif
6817
6818 if(sd->state.showexp) {
6819 char output[256];
6820 sprintf(output,
6821 "Experience Gained Base:%u (%.2f%%) Job:%u (%.2f%%)",base_exp,nextbp*(float)100,job_exp,nextjp*(float)100);
6822 clif_disp_onlyself(sd, output);
6823 }
6824
6825 return true;
6826}
6827
6828/*==========================================
6829 * Returns max level for this character.
6830 *------------------------------------------*/
6831int pc_maxbaselv(const struct map_session_data *sd)
6832{
6833 return pc->max_level[pc->class2idx(sd->status.class_)][0];
6834}
6835
6836int pc_maxjoblv(const struct map_session_data *sd)
6837{
6838 return pc->max_level[pc->class2idx(sd->status.class_)][1];
6839}
6840
6841/*==========================================
6842 * base level exp lookup.
6843 *------------------------------------------*/
6844
6845//Base exp needed for next level.
6846unsigned int pc_nextbaseexp(const struct map_session_data *sd)
6847{
6848 nullpo_ret(sd);
6849
6850 if (sd->status.base_level >= pc->maxbaselv(sd) || sd->status.base_level <= 0)
6851 return 0;
6852
6853 return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-1];
6854}
6855
6856//Base exp needed for this level.
6857unsigned int pc_thisbaseexp(const struct map_session_data *sd)
6858{
6859 if (sd->status.base_level > pc->maxbaselv(sd) || sd->status.base_level <= 1)
6860 return 0;
6861
6862 return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-2];
6863}
6864
6865/*==========================================
6866 * job level exp lookup
6867 * Return:
6868 * 0 = not found
6869 * x = exp for level
6870 *------------------------------------------*/
6871
6872//Job exp needed for next level.
6873unsigned int pc_nextjobexp(const struct map_session_data *sd)
6874{
6875 nullpo_ret(sd);
6876
6877 if (sd->status.job_level >= pc->maxjoblv(sd) || sd->status.job_level <= 0)
6878 return 0;
6879 return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-1];
6880}
6881
6882//Job exp needed for this level.
6883unsigned int pc_thisjobexp(const struct map_session_data *sd)
6884{
6885 if (sd->status.job_level > pc->maxjoblv(sd) || sd->status.job_level <= 1)
6886 return 0;
6887 return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-2];
6888}
6889
6890/// Returns the value of the specified stat.
6891int pc_getstat(struct map_session_data* sd, int type)
6892{
6893 nullpo_retr(-1, sd);
6894
6895 switch( type ) {
6896 case SP_STR: return sd->status.str;
6897 case SP_AGI: return sd->status.agi;
6898 case SP_VIT: return sd->status.vit;
6899 case SP_INT: return sd->status.int_;
6900 case SP_DEX: return sd->status.dex;
6901 case SP_LUK: return sd->status.luk;
6902 default:
6903 return -1;
6904 }
6905}
6906
6907/// Sets the specified stat to the specified value.
6908/// Returns the new value.
6909int pc_setstat(struct map_session_data* sd, int type, int val)
6910{
6911 nullpo_retr(-1, sd);
6912
6913 switch( type ) {
6914 case SP_STR: sd->status.str = val; break;
6915 case SP_AGI: sd->status.agi = val; break;
6916 case SP_VIT: sd->status.vit = val; break;
6917 case SP_INT: sd->status.int_ = val; break;
6918 case SP_DEX: sd->status.dex = val; break;
6919 case SP_LUK: sd->status.luk = val; break;
6920 default:
6921 return -1;
6922 }
6923
6924 return val;
6925}
6926
6927// Calculates the number of status points PC gets when leveling up (from level to level+1)
6928int pc_gets_status_point(int level)
6929{
6930 if (battle_config.use_statpoint_table) //Use values from "db/statpoint.txt"
6931 return (pc->statp[level+1] - pc->statp[level]);
6932 else //Default increase
6933 return ((level+15) / 5);
6934}
6935
6936/// Returns the number of stat points needed to change the specified stat by val.
6937/// If val is negative, returns the number of stat points that would be needed to
6938/// raise the specified stat from (current value - val) to current value.
6939int pc_need_status_point(struct map_session_data* sd, int type, int val)
6940{
6941 int low, high, sp = 0;
6942
6943 if ( val == 0 )
6944 return 0;
6945
6946 low = pc->getstat(sd,type);
6947
6948 if ( low >= pc_maxparameter(sd) && val > 0 )
6949 return 0; // Official servers show '0' when max is reached
6950
6951 high = low + val;
6952
6953 if ( val < 0 )
6954 swap(low, high);
6955
6956 for ( ; low < high; low++ )
6957#ifdef RENEWAL // renewal status point cost formula
6958 sp += (low < 100) ? (2 + (low - 1) / 10) : (16 + 4 * ((low - 100) / 5));
6959#else
6960 sp += ( 1 + (low + 9) / 10 );
6961#endif
6962
6963 return sp;
6964}
6965
6966/**
6967 * Returns the value the specified stat can be increased by with the current
6968 * amount of available status points for the current character's class.
6969 *
6970 * @param sd The target character.
6971 * @param type Stat to verify.
6972 * @return Maximum value the stat could grow by.
6973 */
6974int pc_maxparameterincrease(struct map_session_data* sd, int type) {
6975 int base, final, status_points = sd->status.status_point;
6976
6977 base = final = pc->getstat(sd, type);
6978
6979 while (final <= pc_maxparameter(sd) && status_points >= 0) {
6980#ifdef RENEWAL // renewal status point cost formula
6981 status_points -= (final < 100) ? (2 + (final - 1) / 10) : (16 + 4 * ((final - 100) / 5));
6982#else
6983 status_points -= ( 1 + (final + 9) / 10 );
6984#endif
6985 final++;
6986 }
6987 final--;
6988
6989 return final > base ? final-base : 0;
6990}
6991
6992/**
6993 * Raises a stat by the specified amount.
6994 *
6995 * Obeys max_parameter limits.
6996 * Subtracts status points according to the cost of the increased stat points.
6997 *
6998 * @param sd The target character.
6999 * @param type The stat to change (see enum status_point_types)
7000 * @param increase The stat increase (strictly positive) amount.
7001 * @retval true if the stat was increased by any amount.
7002 * @retval false if there were no changes.
7003 */
7004bool pc_statusup(struct map_session_data* sd, int type, int increase) {
7005 int max_increase = 0, current = 0, needed_points = 0, final_value = 0;
7006
7007 nullpo_ret(sd);
7008
7009 // check conditions
7010 if (type < SP_STR || type > SP_LUK || increase <= 0) {
7011 clif->statusupack(sd, type, 0, 0);
7012 return false;
7013 }
7014
7015 // check limits
7016 current = pc->getstat(sd, type);
7017 max_increase = pc->maxparameterincrease(sd, type);
7018 increase = cap_value(increase, 0, max_increase); // cap to the maximum status points available
7019 if (increase <= 0 || current + increase > pc_maxparameter(sd)) {
7020 clif->statusupack(sd, type, 0, 0);
7021 return false;
7022 }
7023
7024 // check status points
7025 needed_points = pc->need_status_point(sd, type, increase);
7026 if (needed_points < 0 || needed_points > sd->status.status_point) { // Sanity check
7027 clif->statusupack(sd, type, 0, 0);
7028 return false;
7029 }
7030
7031 // set new values
7032 final_value = pc->setstat(sd, type, current + increase);
7033 sd->status.status_point -= needed_points;
7034
7035 status_calc_pc(sd, SCO_NONE);
7036
7037 // update increase cost indicator
7038 clif->updatestatus(sd, SP_USTR + type-SP_STR);
7039
7040 // update statpoint count
7041 clif->updatestatus(sd, SP_STATUSPOINT);
7042
7043 // update stat value
7044 clif->statusupack(sd, type, 1, final_value); // required
7045 if (final_value > 255)
7046 clif->updatestatus(sd, type); // send after the 'ack' to override the truncated value
7047
7048 return true;
7049}
7050
7051/**
7052 * Raises a stat by the specified amount.
7053 *
7054 * Obeys max_parameter limits.
7055 * Does not subtract status points for the cost of the modified stat points.
7056 *
7057 * @param sd The target character.
7058 * @param type The stat to change (see enum status_point_types)
7059 * @param val The stat increase (or decrease) amount.
7060 * @return the stat increase amount.
7061 * @retval 0 if no changes were made.
7062 */
7063int pc_statusup2(struct map_session_data* sd, int type, int val)
7064{
7065 int max, need;
7066 nullpo_ret(sd);
7067
7068 if( type < SP_STR || type > SP_LUK )
7069 {
7070 clif->statusupack(sd,type,0,0);
7071 return 0;
7072 }
7073
7074 need = pc->need_status_point(sd,type,1);
7075
7076 // set new value
7077 max = pc_maxparameter(sd);
7078 val = pc->setstat(sd, type, cap_value(pc->getstat(sd,type) + val, 1, max));
7079
7080 status_calc_pc(sd,SCO_NONE);
7081
7082 // update increase cost indicator
7083 if( need != pc->need_status_point(sd,type,1) )
7084 clif->updatestatus(sd, SP_USTR + type-SP_STR);
7085
7086 // update stat value
7087 clif->statusupack(sd,type,1,val); // required
7088 if( val > 255 )
7089 clif->updatestatus(sd,type); // send after the 'ack' to override the truncated value
7090
7091 return val;
7092}
7093
7094/*==========================================
7095 * Update skill_lv for player sd
7096 * Skill point allocation
7097 *------------------------------------------*/
7098int pc_skillup(struct map_session_data *sd,uint16 skill_id) {
7099 uint16 index = 0;
7100 nullpo_ret(sd);
7101
7102 if( skill_id >= GD_SKILLBASE && skill_id < GD_SKILLBASE+MAX_GUILDSKILL ) {
7103 guild->skillup(sd, skill_id);
7104 return 0;
7105 }
7106
7107 if( skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL && sd->hd ) {
7108 homun->skillup(sd->hd, skill_id);
7109 return 0;
7110 }
7111
7112 if( !(index = skill->get_index(skill_id)) )
7113 return 0;
7114
7115 if( sd->status.skill_point > 0 &&
7116 sd->status.skill[index].id &&
7117 sd->status.skill[index].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
7118 sd->status.skill[index].lv < skill->tree_get_max(skill_id, sd->status.class_) )
7119 {
7120 sd->status.skill[index].lv++;
7121 sd->status.skill_point--;
7122 if( !skill->dbs->db[index].inf )
7123 status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills.
7124 else if( sd->status.skill_point == 0 && (sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )
7125 pc->calc_skilltree(sd); // Required to grant all TK Ranger skills.
7126 else
7127 pc->check_skilltree(sd, skill_id); // Check if a new skill can Lvlup
7128
7129 clif->skillup(sd,skill_id, sd->status.skill[index].lv, 1);
7130 clif->updatestatus(sd,SP_SKILLPOINT);
7131 if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */
7132 clif->updatestatus(sd,SP_CARTINFO);
7133 if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown
7134 clif->skillinfoblock(sd);
7135 } else if( battle_config.skillup_limit ){
7136 if (sd->sktree.second != 0)
7137 clif->msgtable_num(sd, MSG_SKILL_POINTS_LEFT_JOB1, sd->sktree.second);
7138 else if (sd->sktree.third != 0)
7139 clif->msgtable_num(sd, MSG_SKILL_POINTS_LEFT_JOB2, sd->sktree.third);
7140 else if (pc->calc_skillpoint(sd) < 9) /* TODO: official response? */
7141 clif->messagecolor_self(sd->fd, COLOR_RED, "You need the basic skills");
7142 }
7143 return 0;
7144}
7145
7146/*==========================================
7147 * /allskill
7148 *------------------------------------------*/
7149int pc_allskillup(struct map_session_data *sd)
7150{
7151 int i;
7152
7153 nullpo_ret(sd);
7154
7155 for(i=0;i<MAX_SKILL;i++){
7156 if (sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED) {
7157 sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
7158 sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
7159 if (sd->status.skill[i].lv == 0)
7160 sd->status.skill[i].id = 0;
7161 }
7162 }
7163
7164 if (pc_has_permission(sd, PC_PERM_ALL_SKILL)) { //Get ALL skills except npc/guild ones. [Skotlex]
7165 //and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage]
7166 for(i=0;i<MAX_SKILL;i++){
7167 switch( skill->dbs->db[i].nameid ) {
7168 case SG_DEVIL:
7169 case MO_TRIPLEATTACK:
7170 case RG_SNATCHER:
7171 continue;
7172 default:
7173 if( !(skill->dbs->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) )
7174 if ( ( sd->status.skill[i].lv = skill->dbs->db[i].max ) )//Nonexistant skills should return a max of 0 anyway.
7175 sd->status.skill[i].id = skill->dbs->db[i].nameid;
7176 }
7177 }
7178 } else {
7179 int id;
7180 for (i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[pc->class2idx(sd->status.class_)][i].id) > 0; i++) {
7181 int idx = pc->skill_tree[pc->class2idx(sd->status.class_)][i].idx;
7182 int inf2 = skill->dbs->db[idx].inf2;
7183 if (
7184 (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) ||
7185 (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) ||
7186 id==SG_DEVIL
7187 )
7188 continue; //Cannot be learned normally.
7189
7190 sd->status.skill[idx].id = id;
7191 sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_); // celest
7192 }
7193 }
7194 status_calc_pc(sd,SCO_NONE);
7195 //Required because if you could level up all skills previously,
7196 //the update will not be sent as only the lv variable changes.
7197 clif->skillinfoblock(sd);
7198 return 0;
7199}
7200
7201/*==========================================
7202 * /resetlvl
7203 *------------------------------------------*/
7204int pc_resetlvl(struct map_session_data* sd,int type)
7205{
7206 int i;
7207
7208 nullpo_ret(sd);
7209
7210 if (type != 3) //Also reset skills
7211 pc->resetskill(sd, PCRESETSKILL_NONE);
7212
7213 if(type == 1) {
7214 sd->status.skill_point=0;
7215 sd->status.base_level=1;
7216 sd->status.job_level=1;
7217 sd->status.base_exp=0;
7218 sd->status.job_exp=0;
7219 if(sd->sc.option !=0)
7220 sd->sc.option = 0;
7221
7222 sd->status.str=1;
7223 sd->status.agi=1;
7224 sd->status.vit=1;
7225 sd->status.int_=1;
7226 sd->status.dex=1;
7227 sd->status.luk=1;
7228 if(sd->status.class_ == JOB_NOVICE_HIGH) {
7229 sd->status.status_point=100; // not 88 [celest]
7230 // give platinum skills upon changing
7231 pc->skill(sd, NV_FIRSTAID, 1, SKILL_GRANT_PERMANENT);
7232 pc->skill(sd, NV_TRICKDEAD, 1, SKILL_GRANT_PERMANENT);
7233 }
7234 }
7235
7236 if(type == 2){
7237 sd->status.skill_point=0;
7238 sd->status.base_level=1;
7239 sd->status.job_level=1;
7240 sd->status.base_exp=0;
7241 sd->status.job_exp=0;
7242 }
7243 if(type == 3){
7244 sd->status.base_level=1;
7245 sd->status.base_exp=0;
7246 }
7247 if(type == 4){
7248 sd->status.job_level=1;
7249 sd->status.job_exp=0;
7250 }
7251
7252 clif->updatestatus(sd,SP_STATUSPOINT);
7253 clif->updatestatus(sd,SP_STR);
7254 clif->updatestatus(sd,SP_AGI);
7255 clif->updatestatus(sd,SP_VIT);
7256 clif->updatestatus(sd,SP_INT);
7257 clif->updatestatus(sd,SP_DEX);
7258 clif->updatestatus(sd,SP_LUK);
7259 clif->updatestatus(sd,SP_BASELEVEL);
7260 clif->updatestatus(sd,SP_JOBLEVEL);
7261 clif->updatestatus(sd,SP_STATUSPOINT);
7262 clif->updatestatus(sd,SP_BASEEXP);
7263 clif->updatestatus(sd,SP_JOBEXP);
7264 clif->updatestatus(sd,SP_NEXTBASEEXP);
7265 clif->updatestatus(sd,SP_NEXTJOBEXP);
7266 clif->updatestatus(sd,SP_SKILLPOINT);
7267
7268 clif->updatestatus(sd,SP_USTR); // Updates needed stat points - Valaris
7269 clif->updatestatus(sd,SP_UAGI);
7270 clif->updatestatus(sd,SP_UVIT);
7271 clif->updatestatus(sd,SP_UINT);
7272 clif->updatestatus(sd,SP_UDEX);
7273 clif->updatestatus(sd,SP_ULUK); // End Addition
7274
7275 for(i=0;i<EQI_MAX;i++) { // unequip items that can't be equipped by base 1 [Valaris]
7276 if(sd->equip_index[i] >= 0)
7277 if(!pc->isequip(sd,sd->equip_index[i]))
7278 pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
7279 }
7280
7281 if ((type == 1 || type == 2 || type == 3) && sd->status.party_id)
7282 party->send_levelup(sd);
7283
7284 status_calc_pc(sd,SCO_FORCE);
7285 clif->skillinfoblock(sd);
7286
7287 return 0;
7288}
7289/*==========================================
7290 * /resetstate
7291 *------------------------------------------*/
7292int pc_resetstate(struct map_session_data* sd)
7293{
7294 nullpo_ret(sd);
7295
7296 if (battle_config.use_statpoint_table) {
7297 // New statpoint table used here - Dexity
7298 if (sd->status.base_level > MAX_LEVEL) {
7299 //pc->statp[] goes out of bounds, can't reset!
7300 ShowError("pc_resetstate: Can't reset stats of %d:%d, the base level (%d) is greater than the max level supported (%d)\n",
7301 sd->status.account_id, sd->status.char_id, sd->status.base_level, MAX_LEVEL);
7302 return 0;
7303 }
7304
7305 sd->status.status_point = pc->statp[sd->status.base_level] + ((sd->class_&JOBL_UPPER) ? 52 : 0); // extra 52+48=100 stat points
7306 }
7307 else
7308 {
7309 int add=0;
7310 add += pc->need_status_point(sd, SP_STR, 1-pc->getstat(sd, SP_STR));
7311 add += pc->need_status_point(sd, SP_AGI, 1-pc->getstat(sd, SP_AGI));
7312 add += pc->need_status_point(sd, SP_VIT, 1-pc->getstat(sd, SP_VIT));
7313 add += pc->need_status_point(sd, SP_INT, 1-pc->getstat(sd, SP_INT));
7314 add += pc->need_status_point(sd, SP_DEX, 1-pc->getstat(sd, SP_DEX));
7315 add += pc->need_status_point(sd, SP_LUK, 1-pc->getstat(sd, SP_LUK));
7316
7317 sd->status.status_point+=add;
7318 }
7319
7320 pc->setstat(sd, SP_STR, 1);
7321 pc->setstat(sd, SP_AGI, 1);
7322 pc->setstat(sd, SP_VIT, 1);
7323 pc->setstat(sd, SP_INT, 1);
7324 pc->setstat(sd, SP_DEX, 1);
7325 pc->setstat(sd, SP_LUK, 1);
7326
7327 clif->updatestatus(sd,SP_STR);
7328 clif->updatestatus(sd,SP_AGI);
7329 clif->updatestatus(sd,SP_VIT);
7330 clif->updatestatus(sd,SP_INT);
7331 clif->updatestatus(sd,SP_DEX);
7332 clif->updatestatus(sd,SP_LUK);
7333
7334 clif->updatestatus(sd,SP_USTR); // Updates needed stat points - Valaris
7335 clif->updatestatus(sd,SP_UAGI);
7336 clif->updatestatus(sd,SP_UVIT);
7337 clif->updatestatus(sd,SP_UINT);
7338 clif->updatestatus(sd,SP_UDEX);
7339 clif->updatestatus(sd,SP_ULUK); // End Addition
7340
7341 clif->updatestatus(sd,SP_STATUSPOINT);
7342
7343 if( sd->mission_mobid ) { //bugreport:2200
7344 sd->mission_mobid = 0;
7345 sd->mission_count = 0;
7346 pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), 0);
7347 }
7348
7349 status_calc_pc(sd,SCO_NONE);
7350
7351 return 1;
7352}
7353
7354/*==========================================
7355 * /resetskill
7356 * @param flag: @see enum pc_resetskill_flag
7357 *------------------------------------------*/
7358int pc_resetskill(struct map_session_data* sd, int flag)
7359{
7360 int i, inf2, skill_point=0;
7361 nullpo_ret(sd);
7362
7363 if( flag&PCRESETSKILL_CHSEX && (sd->class_&MAPID_UPPERMASK) != MAPID_BARDDANCER )
7364 return 0;
7365
7366 if( !(flag&PCRESETSKILL_RECOUNT) ) { //Remove stuff lost when resetting skills.
7367
7368 /**
7369 * It has been confirmed on official server that when you reset skills with a ranked tweakwon your skills are not reset (because you have all of them anyway)
7370 **/
7371 if( (sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )
7372 return 0;
7373
7374 if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex]
7375 clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1);
7376 i = sd->sc.option;
7377 if( i&OPTION_RIDING && pc->checkskill(sd, KN_RIDING) )
7378 i &= ~OPTION_RIDING;
7379 if( i&OPTION_FALCON && pc->checkskill(sd, HT_FALCON) )
7380 i &= ~OPTION_FALCON;
7381 if( i&OPTION_DRAGON && pc->checkskill(sd, RK_DRAGONTRAINING) )
7382 i &= ~OPTION_DRAGON;
7383 if( i&OPTION_WUG && pc->checkskill(sd, RA_WUGMASTERY) )
7384 i &= ~OPTION_WUG;
7385 if( i&OPTION_WUGRIDER && pc->checkskill(sd, RA_WUGRIDER) )
7386 i &= ~OPTION_WUGRIDER;
7387 if( i&OPTION_MADOGEAR && ( sd->class_&MAPID_THIRDMASK ) == MAPID_MECHANIC )
7388 i &= ~OPTION_MADOGEAR;
7389#ifndef NEW_CARTS
7390 if( i&OPTION_CART && pc->checkskill(sd, MC_PUSHCART) )
7391 i &= ~OPTION_CART;
7392#else
7393 if( sd->sc.data[SC_PUSH_CART] )
7394 pc->setcart(sd, 0);
7395#endif
7396 if( i != sd->sc.option )
7397 pc->setoption(sd, i);
7398
7399 if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) )
7400 homun->vaporize(sd, HOM_ST_REST);
7401 }
7402
7403 for( i = 1; i < MAX_SKILL; i++ ) {
7404 // FIXME: We're looping on i = [1..MAX_SKILL-1] (which makes sense as index for sd->status.skill[]) but then we're using the
7405 // same i to access skill->dbs->db[], and especially to check skill_ischangesex(). This is wrong.
7406 uint16 skill_id = 0;
7407 int lv = sd->status.skill[i].lv;
7408 if (lv < 1) continue;
7409
7410 inf2 = skill->dbs->db[i].inf2;
7411
7412 if( inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL) ) //Avoid reseting wedding/linker skills.
7413 continue;
7414
7415 skill_id = skill->dbs->db[i].nameid;
7416
7417 // Don't reset trick dead if not a novice/baby
7418 if( skill_id == NV_TRICKDEAD && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) {
7419 sd->status.skill[i].lv = 0;
7420 sd->status.skill[i].flag = 0;
7421 continue;
7422 }
7423
7424 // do not reset basic skill
7425 if( skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE )
7426 continue;
7427
7428 if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED )
7429 continue;
7430
7431 if( flag&PCRESETSKILL_CHSEX && !skill_ischangesex(i) )
7432 continue;
7433
7434 if( inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn ) {
7435 //Only handle quest skills in a special way when you can't learn them manually
7436 if( battle_config.quest_skill_reset && !(flag&PCRESETSKILL_RECOUNT) ) { //Wipe them
7437 sd->status.skill[i].lv = 0;
7438 sd->status.skill[i].flag = 0;
7439 }
7440 continue;
7441 }
7442 if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT )
7443 skill_point += lv;
7444 else if( sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 )
7445 skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
7446
7447 if( !(flag&PCRESETSKILL_RECOUNT) ) {// reset
7448 sd->status.skill[i].lv = 0;
7449 sd->status.skill[i].flag = 0;
7450 }
7451 }
7452
7453 if( flag&PCRESETSKILL_RECOUNT || !skill_point ) return skill_point;
7454
7455 sd->status.skill_point += skill_point;
7456
7457 if (!(flag&PCRESETSKILL_RECOUNT)) {
7458 // Remove all SCs that can't be inactivated without a skill
7459 if( sd->sc.data[SC_STORMKICK_READY] )
7460 status_change_end(&sd->bl, SC_STORMKICK_READY, INVALID_TIMER);
7461 if( sd->sc.data[SC_DOWNKICK_READY] )
7462 status_change_end(&sd->bl, SC_DOWNKICK_READY, INVALID_TIMER);
7463 if( sd->sc.data[SC_TURNKICK_READY] )
7464 status_change_end(&sd->bl, SC_TURNKICK_READY, INVALID_TIMER);
7465 if( sd->sc.data[SC_COUNTERKICK_READY] )
7466 status_change_end(&sd->bl, SC_COUNTERKICK_READY, INVALID_TIMER);
7467 if( sd->sc.data[SC_DODGE_READY] )
7468 status_change_end(&sd->bl, SC_DODGE_READY, INVALID_TIMER);
7469 }
7470
7471 if (flag&PCRESETSKILL_RESYNC) {
7472 clif->updatestatus(sd,SP_SKILLPOINT);
7473 clif->skillinfoblock(sd);
7474 status_calc_pc(sd,SCO_FORCE);
7475 }
7476
7477 return skill_point;
7478}
7479
7480/*==========================================
7481 * /resetfeel [Komurka]
7482 *------------------------------------------*/
7483int pc_resetfeel(struct map_session_data* sd)
7484{
7485 int i;
7486 nullpo_ret(sd);
7487
7488 for (i=0; i<MAX_PC_FEELHATE; i++)
7489 {
7490 sd->feel_map[i].m = -1;
7491 sd->feel_map[i].index = 0;
7492 pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),0);
7493 }
7494
7495 return 0;
7496}
7497
7498int pc_resethate(struct map_session_data* sd)
7499{
7500 int i;
7501 nullpo_ret(sd);
7502
7503 for (i = 0; i < MAX_PC_FEELHATE; i++) {
7504 sd->hate_mob[i] = -1;
7505 pc_setglobalreg(sd,script->add_str(pc->sg_info[i].hate_var),0);
7506 }
7507 return 0;
7508}
7509
7510int pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id)
7511{
7512 int i, bonus = 0;
7513 nullpo_ret(sd);
7514
7515 ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == skill_id);
7516 if( i < ARRAYLENGTH(sd->skillatk) ) bonus = sd->skillatk[i].val;
7517
7518 if(sd->sc.data[SC_PYROTECHNIC_OPTION] || sd->sc.data[SC_AQUAPLAY_OPTION])
7519 bonus += 10;
7520
7521 return bonus;
7522}
7523
7524int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) {
7525 int i, bonus = sd->bonus.add_heal_rate;
7526
7527 if( bonus ) {
7528 switch( skill_id ) {
7529 case AL_HEAL: if( !(battle_config.skill_add_heal_rate&1) ) bonus = 0; break;
7530 case PR_SANCTUARY: if( !(battle_config.skill_add_heal_rate&2) ) bonus = 0; break;
7531 case AM_POTIONPITCHER: if( !(battle_config.skill_add_heal_rate&4) ) bonus = 0; break;
7532 case CR_SLIMPITCHER: if( !(battle_config.skill_add_heal_rate&8) ) bonus = 0; break;
7533 case BA_APPLEIDUN: if( !(battle_config.skill_add_heal_rate&16)) bonus = 0; break;
7534 }
7535 }
7536
7537 ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == skill_id);
7538
7539 if( i < ARRAYLENGTH(sd->skillheal) )
7540 bonus += sd->skillheal[i].val;
7541
7542 return bonus;
7543}
7544
7545int pc_skillheal2_bonus(struct map_session_data *sd, uint16 skill_id) {
7546 int i, bonus = sd->bonus.add_heal2_rate;
7547
7548 ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == skill_id);
7549
7550 if( i < ARRAYLENGTH(sd->skillheal2) )
7551 bonus += sd->skillheal2[i].val;
7552
7553 return bonus;
7554}
7555
7556void pc_respawn(struct map_session_data* sd, clr_type clrtype)
7557{
7558 if( !pc_isdead(sd) )
7559 return; // not applicable
7560 if( sd->bg_id && bg->member_respawn(sd) )
7561 return; // member revived by battleground
7562
7563 pc->setstand(sd);
7564 pc->setrestartvalue(sd,3);
7565 if( pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, clrtype) )
7566 clif->resurrection(&sd->bl, 1); //If warping fails, send a normal stand up packet.
7567}
7568
7569int pc_respawn_timer(int tid, int64 tick, int id, intptr_t data) {
7570 struct map_session_data *sd = map->id2sd(id);
7571 if( sd != NULL )
7572 {
7573 sd->pvp_point=0;
7574 pc->respawn(sd,CLR_OUTSIGHT);
7575 }
7576
7577 return 0;
7578}
7579
7580/*==========================================
7581 * Invoked when a player has received damage
7582 *------------------------------------------*/
7583void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp)
7584{
7585 if (sp) clif->updatestatus(sd,SP_SP);
7586 if (hp) clif->updatestatus(sd,SP_HP);
7587 else return;
7588
7589 if( !src || src == &sd->bl )
7590 return;
7591
7592 if( pc_issit(sd) ) {
7593 pc->setstand(sd);
7594 skill->sit(sd,0);
7595 }
7596
7597 if( sd->progressbar.npc_id ){
7598 clif->progressbar_abort(sd);
7599 sd->state.workinprogress = 0;
7600 }
7601
7602 if( sd->status.pet_id > 0 && sd->pd && battle_config.pet_damage_support )
7603 pet->target_check(sd,src,1);
7604
7605 if( sd->status.ele_id > 0 )
7606 elemental->set_target(sd,src);
7607
7608 sd->canlog_tick = timer->gettick();
7609}
7610
7611/*==========================================
7612 * Invoked when a player has negative current hp
7613 *------------------------------------------*/
7614int pc_dead(struct map_session_data *sd,struct block_list *src) {
7615 int i=0,j=0;
7616 int64 tick = timer->gettick();
7617
7618 nullpo_retr(0, sd);
7619
7620 for (j = 0; j < MAX_PC_DEVOTION; j++) {
7621 if (sd->devotion[j]) {
7622 struct map_session_data *devsd = map->id2sd(sd->devotion[j]);
7623 if (devsd)
7624 status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER);
7625 sd->devotion[j] = 0;
7626 }
7627 }
7628
7629 if(sd->status.pet_id > 0 && sd->pd) {
7630 struct pet_data *pd = sd->pd;
7631 if( !map->list[sd->bl.m].flag.noexppenalty ) {
7632 pet->set_intimate(pd, pd->pet.intimate - pd->petDB->die);
7633 if( pd->pet.intimate < 0 )
7634 pd->pet.intimate = 0;
7635 clif->send_petdata(sd,sd->pd,1,pd->pet.intimate);
7636 }
7637 if( sd->pd->target_id ) // Unlock all targets...
7638 pet->unlocktarget(sd->pd);
7639 }
7640
7641 if (sd->status.hom_id > 0){
7642 if(battle_config.homunculus_auto_vapor && sd->hd)
7643 homun->vaporize(sd, HOM_ST_REST);
7644 }
7645
7646 if( sd->md )
7647 mercenary->delete(sd->md, 3); // Your mercenary soldier has ran away.
7648
7649 if( sd->ed )
7650 elemental->delete(sd->ed, 0);
7651
7652 // Leave duel if you die [LuzZza]
7653 if(battle_config.duel_autoleave_when_die) {
7654 if(sd->duel_group > 0)
7655 duel->leave(sd->duel_group, sd);
7656 if(sd->duel_invite > 0)
7657 duel->reject(sd->duel_invite, sd);
7658 }
7659
7660 if (sd->npc_id && sd->st && sd->st->state != RUN)
7661 npc->event_dequeue(sd);
7662
7663 pc_setglobalreg(sd,script->add_str("PC_DIE_COUNTER"),sd->die_counter+1);
7664 pc->setparam(sd, SP_KILLERRID, src?src->id:0);
7665
7666 if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */
7667 struct battleground_data *bgd;
7668 if( (bgd = bg->team_search(sd->bg_id)) != NULL && bgd->die_event[0] )
7669 npc->event(sd, bgd->die_event, 0);
7670 }
7671
7672 for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++ ) {
7673 struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
7674 if (queue && queue->event_death[0] != '\0')
7675 npc->event(sd, queue->event_death, 0);
7676 }
7677
7678 npc->script_event(sd,NPCE_DIE);
7679
7680 // Clear anything NPC-related when you die and was interacting with one.
7681 if ( (sd->npc_id || sd->npc_shopid) && sd->state.dialog) {
7682 if (sd->state.using_fake_npc) {
7683 clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
7684 sd->state.using_fake_npc = 0;
7685 }
7686 if (sd->state.menu_or_input)
7687 sd->state.menu_or_input = 0;
7688 if (sd->npc_menu)
7689 sd->npc_menu = 0;
7690
7691 sd->npc_id = 0;
7692 sd->npc_shopid = 0;
7693 if (sd->st && sd->st->state != END)
7694 sd->st->state = END;
7695 }
7696
7697 /* e.g. not killed through pc->damage */
7698 if( pc_issit(sd) ) {
7699 clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
7700 }
7701
7702 pc_setdead(sd);
7703 //Reset menu skills/item skills
7704 if (sd->skillitem)
7705 sd->skillitem = sd->skillitemlv = 0;
7706 if (sd->menuskill_id)
7707 sd->menuskill_id = sd->menuskill_val = 0;
7708 //Reset ticks.
7709 sd->hp_loss.tick = sd->sp_loss.tick = sd->hp_regen.tick = sd->sp_regen.tick = 0;
7710
7711 if ( sd->spiritball )
7712 pc->delspiritball(sd, sd->spiritball, 0);
7713 if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
7714 pc->del_charm(sd, sd->charm_count, sd->charm_type);
7715
7716 if (src != NULL) {
7717 switch (src->type) {
7718 case BL_MOB:
7719 {
7720 struct mob_data *md = BL_UCAST(BL_MOB, src);
7721 if (md->target_id==sd->bl.id)
7722 mob->unlocktarget(md,tick);
7723 if (battle_config.mobs_level_up && md->status.hp
7724 && md->level < pc->maxbaselv(sd)
7725 && !md->guardian_data && md->special_state.ai == AI_NONE// Guardians/summons should not level. [Skotlex]
7726 ) {
7727 // monster level up [Valaris]
7728 clif->misceffect(&md->bl,0);
7729 md->level++;
7730 status_calc_mob(md, SCO_NONE);
7731 status_percent_heal(src,10,0);
7732
7733 if( battle_config.show_mob_info&4 )
7734 {// update name with new level
7735 clif->charnameack(0, &md->bl);
7736 }
7737 }
7738 src = battle->get_master(src); // Maybe Player Summon
7739 }
7740 break;
7741 case BL_PET: //Pass on to master...
7742 src = &BL_UCAST(BL_PET, src)->msd->bl;
7743 break;
7744 case BL_HOM:
7745 src = &BL_UCAST(BL_HOM, src)->master->bl;
7746 break;
7747 case BL_MER:
7748 src = &BL_UCAST(BL_MER, src)->master->bl;
7749 break;
7750 }
7751 }
7752
7753 if (src != NULL && src->type == BL_PC) {
7754 struct map_session_data *ssd = BL_UCAST(BL_PC, src);
7755 pc->setparam(ssd, SP_KILLEDRID, sd->bl.id);
7756 npc->script_event(ssd, NPCE_KILLPC);
7757
7758 if (battle_config.pk_mode&2) {
7759 ssd->status.manner -= 5;
7760 if(ssd->status.manner < 0)
7761 sc_start(NULL,src,SC_NOCHAT,100,0,0);
7762#if 0
7763 // PK/Karma system code (not enabled yet) [celest]
7764 // originally from Kade Online, so i don't know if any of these is correct ^^;
7765 // note: karma is measured REVERSE, so more karma = more 'evil' / less honourable,
7766 // karma going down = more 'good' / more honourable.
7767 // The Karma System way...
7768
7769 if (sd->status.karma > ssd->status.karma) {
7770 // If player killed was more evil
7771 sd->status.karma--;
7772 ssd->status.karma--;
7773 }
7774 else if (sd->status.karma < ssd->status.karma) // If player killed was more good
7775 ssd->status.karma++;
7776
7777 // or the PK System way...
7778
7779 if (sd->status.karma > 0) // player killed is dishonourable?
7780 ssd->status.karma--; // honour points earned
7781 sd->status.karma++; // honour points lost
7782
7783 // To-do: Receive exp on certain occasions
7784#endif
7785 }
7786 }
7787
7788 if( battle_config.bone_drop==2
7789 || (battle_config.bone_drop==1 && map->list[sd->bl.m].flag.pvp)
7790 ) {
7791 struct item item_tmp;
7792 memset(&item_tmp,0,sizeof(item_tmp));
7793 item_tmp.nameid=ITEMID_SKULL_;
7794 item_tmp.identify=1;
7795 item_tmp.card[0]=CARD0_CREATE;
7796 item_tmp.card[1]=0;
7797 item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId
7798 item_tmp.card[3]=GetWord(sd->status.char_id,1);
7799 map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
7800 }
7801
7802 // activate Steel body if a super novice dies at 99+% exp [celest]
7803 if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) {
7804 unsigned int next = pc->nextbaseexp(sd);
7805 if( next == 0 ) next = pc->thisbaseexp(sd);
7806 if( get_percentage(sd->status.base_exp,next) >= 99 ) {
7807 sd->state.snovice_dead_flag = 1;
7808 pc->setstand(sd);
7809 status_percent_heal(&sd->bl, 100, 100);
7810 clif->resurrection(&sd->bl, 1);
7811 if(battle_config.pc_invincible_time)
7812 pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
7813 sc_start(NULL,&sd->bl,status->skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1));
7814 if(map_flag_gvg2(sd->bl.m))
7815 pc->respawn_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0);
7816 return 0;
7817 }
7818 }
7819
7820 // changed penalty options, added death by player if pk_mode [Valaris]
7821 if( battle_config.death_penalty_type
7822 && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty
7823 && !map->list[sd->bl.m].flag.noexppenalty && !map_flag_gvg2(sd->bl.m)
7824 && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]
7825 ) {
7826 if (battle_config.death_penalty_base > 0) {
7827 unsigned int base_penalty = 0;
7828 switch (battle_config.death_penalty_type) {
7829 case 1:
7830 base_penalty = (unsigned int) apply_percentrate64(pc->nextbaseexp(sd), battle_config.death_penalty_base, 10000);
7831 break;
7832 case 2:
7833 base_penalty = (unsigned int) apply_percentrate64(sd->status.base_exp, battle_config.death_penalty_base, 10000);
7834 break;
7835 }
7836
7837 if (base_penalty != 0) {
7838 if (battle_config.pk_mode && src && src->type==BL_PC)
7839 base_penalty*=2;
7840 if( sd->status.mod_death != 100 )
7841 base_penalty = base_penalty * sd->status.mod_death / 100;
7842 sd->status.base_exp -= min(sd->status.base_exp, base_penalty);
7843 clif->updatestatus(sd,SP_BASEEXP);
7844 }
7845 }
7846
7847 if(battle_config.death_penalty_job > 0) {
7848 unsigned int job_penalty = 0;
7849
7850 switch (battle_config.death_penalty_type) {
7851 case 1:
7852 job_penalty = (unsigned int) apply_percentrate64(pc->nextjobexp(sd), battle_config.death_penalty_job, 10000);
7853 break;
7854 case 2:
7855 job_penalty = (unsigned int) apply_percentrate64(sd->status.job_exp, battle_config.death_penalty_job, 10000);
7856 break;
7857 }
7858
7859 if (job_penalty != 0) {
7860 if (battle_config.pk_mode && src && src->type==BL_PC)
7861 job_penalty*=2;
7862 if( sd->status.mod_death != 100 )
7863 job_penalty = job_penalty * sd->status.mod_death / 100;
7864 sd->status.job_exp -= min(sd->status.job_exp, job_penalty);
7865 clif->updatestatus(sd,SP_JOBEXP);
7866 }
7867 }
7868
7869 if (battle_config.zeny_penalty > 0 && !map->list[sd->bl.m].flag.nozenypenalty) {
7870 int zeny_penalty = apply_percentrate(sd->status.zeny, battle_config.zeny_penalty, 10000);
7871 if (zeny_penalty != 0)
7872 pc->payzeny(sd, zeny_penalty, LOG_TYPE_PICKDROP_PLAYER, NULL);
7873 }
7874 }
7875
7876 if(map->list[sd->bl.m].flag.pvp_nightmaredrop) {
7877 // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
7878 for(j=0;j<map->list[sd->bl.m].drop_list_count;j++){
7879 int id = map->list[sd->bl.m].drop_list[j].drop_id;
7880 int type = map->list[sd->bl.m].drop_list[j].drop_type;
7881 int per = map->list[sd->bl.m].drop_list[j].drop_per;
7882 if(id == 0)
7883 continue;
7884 if(id == -1){
7885 int eq_num=0,eq_n[MAX_INVENTORY],k;
7886 memset(eq_n,0,sizeof(eq_n));
7887 for(i=0;i<MAX_INVENTORY;i++){
7888 if( (type == 1 && !sd->status.inventory[i].equip)
7889 || (type == 2 && sd->status.inventory[i].equip)
7890 || type == 3)
7891 {
7892 ARR_FIND( 0, MAX_INVENTORY, k, eq_n[k] <= 0 );
7893 if( k < MAX_INVENTORY )
7894 eq_n[k] = i;
7895
7896 eq_num++;
7897 }
7898 }
7899 if(eq_num > 0){
7900 int n = eq_n[rnd()%eq_num];
7901 if(rnd()%10000 < per){
7902 if(sd->status.inventory[n].equip)
7903 pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
7904 pc->dropitem(sd,n,1);
7905 }
7906 }
7907 }
7908 else if(id > 0){
7909 for(i=0;i<MAX_INVENTORY;i++){
7910 if(sd->status.inventory[i].nameid == id
7911 && rnd()%10000 < per
7912 && ((type == 1 && !sd->status.inventory[i].equip)
7913 || (type == 2 && sd->status.inventory[i].equip)
7914 || type == 3) ){
7915 if(sd->status.inventory[i].equip)
7916 pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
7917 pc->dropitem(sd,i,1);
7918 break;
7919 }
7920 }
7921 }
7922 }
7923 }
7924
7925 // Remove autotrade to prevent autotrading from save point
7926 if( (sd->state.standalone || sd->state.autotrade)
7927 && (map->list[sd->bl.m].flag.pvp || map->list[sd->bl.m].flag.gvg)
7928 ) {
7929 sd->state.autotrade = 0;
7930 sd->state.standalone = 0;
7931 pc->autotrade_update(sd,PAUC_REMOVE);
7932 map->quit(sd);
7933 }
7934
7935 // pvp
7936 // disable certain pvp functions on pk_mode [Valaris]
7937 if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) {
7938 sd->pvp_point -= 5;
7939 sd->pvp_lost++;
7940 if (src != NULL && src->type == BL_PC) {
7941 struct map_session_data *ssd = BL_UCAST(BL_PC, src);
7942 ssd->pvp_point++;
7943 ssd->pvp_won++;
7944 }
7945 if( sd->pvp_point < 0 )
7946 {
7947 timer->add(tick+1, pc->respawn_timer,sd->bl.id,0);
7948 return 1|8;
7949 }
7950 }
7951 //GvG
7952 if( map_flag_gvg2(sd->bl.m) ) {
7953 timer->add(tick+1, pc->respawn_timer, sd->bl.id, 0);
7954 return 1|8;
7955 } else if( sd->bg_id ) {
7956 struct battleground_data *bgd = bg->team_search(sd->bg_id);
7957 if( bgd && bgd->mapindex > 0 ) { // Respawn by BG
7958 timer->add(tick+1000, pc->respawn_timer, sd->bl.id, 0);
7959 return 1|8;
7960 }
7961 }
7962
7963 //Reset "can log out" tick.
7964 if( battle_config.prevent_logout )
7965 sd->canlog_tick = timer->gettick() - battle_config.prevent_logout;
7966
7967 return 1;
7968}
7969
7970void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) {
7971 nullpo_retv(sd);
7972 if(hp) clif->updatestatus(sd,SP_HP);
7973 if(sp) clif->updatestatus(sd,SP_SP);
7974
7975 pc->setstand(sd);
7976 if(battle_config.pc_invincible_time > 0)
7977 pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
7978
7979 if( sd->state.gmaster_flag ) {
7980 guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP));
7981 guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS));
7982 guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD));
7983 guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES));
7984 }
7985}
7986// script
7987//
7988/*==========================================
7989 * script reading pc status registry
7990 *------------------------------------------*/
7991int pc_readparam(const struct map_session_data *sd, int type)
7992{
7993 int val = 0;
7994
7995 nullpo_ret(sd);
7996
7997 switch(type) {
7998 case SP_SKILLPOINT: val = sd->status.skill_point; break;
7999 case SP_STATUSPOINT: val = sd->status.status_point; break;
8000 case SP_ZENY: val = sd->status.zeny; break;
8001 case SP_BASELEVEL: val = sd->status.base_level; break;
8002 case SP_JOBLEVEL: val = sd->status.job_level; break;
8003 case SP_CLASS: val = sd->status.class_; break;
8004 case SP_BASEJOB: val = pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex); break; //Base job, extracting upper type.
8005 case SP_UPPER: val = (sd->class_&JOBL_UPPER) ? 1 : ((sd->class_&JOBL_BABY) ? 2 : 0); break;
8006 case SP_BASECLASS: val = pc->mapid2jobid(sd->class_&MAPID_BASEMASK, sd->status.sex); break; //Extract base class tree. [Skotlex]
8007 case SP_SEX: val = sd->status.sex; break;
8008 case SP_WEIGHT: val = sd->weight; break;
8009 case SP_MAXWEIGHT: val = sd->max_weight; break;
8010 case SP_BASEEXP: val = sd->status.base_exp; break;
8011 case SP_JOBEXP: val = sd->status.job_exp; break;
8012 case SP_NEXTBASEEXP: val = pc->nextbaseexp(sd); break;
8013 case SP_NEXTJOBEXP: val = pc->nextjobexp(sd); break;
8014 case SP_HP: val = sd->battle_status.hp; break;
8015 case SP_MAXHP: val = sd->battle_status.max_hp; break;
8016 case SP_SP: val = sd->battle_status.sp; break;
8017 case SP_MAXSP: val = sd->battle_status.max_sp; break;
8018 case SP_STR: val = sd->status.str; break;
8019 case SP_AGI: val = sd->status.agi; break;
8020 case SP_VIT: val = sd->status.vit; break;
8021 case SP_INT: val = sd->status.int_; break;
8022 case SP_DEX: val = sd->status.dex; break;
8023 case SP_LUK: val = sd->status.luk; break;
8024 case SP_KARMA: val = sd->status.karma; break;
8025 case SP_MANNER: val = sd->status.manner; break;
8026 case SP_FAME: val = sd->status.fame; break;
8027 case SP_KILLERRID: val = sd->killerrid; break;
8028 case SP_KILLEDRID: val = sd->killedrid; break;
8029 case SP_SLOTCHANGE: val = sd->status.slotchange; break;
8030 case SP_CHARRENAME: val = sd->status.rename; break;
8031 case SP_MOD_EXP: val = sd->status.mod_exp; break;
8032 case SP_MOD_DROP: val = sd->status.mod_drop; break;
8033 case SP_MOD_DEATH: val = sd->status.mod_death; break;
8034 case SP_CRITICAL: val = sd->battle_status.cri/10; break;
8035 case SP_ASPD: val = (2000-sd->battle_status.amotion)/10; break;
8036 case SP_BASE_ATK: val = sd->battle_status.batk; break;
8037 case SP_DEF1: val = sd->battle_status.def; break;
8038 case SP_DEF2: val = sd->battle_status.def2; break;
8039 case SP_MDEF1: val = sd->battle_status.mdef; break;
8040 case SP_MDEF2: val = sd->battle_status.mdef2; break;
8041 case SP_HIT: val = sd->battle_status.hit; break;
8042 case SP_FLEE1: val = sd->battle_status.flee; break;
8043 case SP_FLEE2: val = sd->battle_status.flee2; break;
8044 case SP_DEFELE: val = sd->battle_status.def_ele; break;
8045#ifndef RENEWAL_CAST
8046 case SP_VARCASTRATE:
8047#endif
8048 case SP_CASTRATE:
8049 val = sd->castrate;
8050 break;
8051 case SP_MAXHPRATE: val = sd->hprate; break;
8052 case SP_MAXSPRATE: val = sd->sprate; break;
8053 case SP_SPRATE: val = sd->dsprate; break;
8054 case SP_SPEED_RATE: val = sd->bonus.speed_rate; break;
8055 case SP_SPEED_ADDRATE: val = sd->bonus.speed_add_rate; break;
8056 case SP_ASPD_RATE:
8057#ifndef RENEWAL_ASPD
8058 val = sd->battle_status.aspd_rate;
8059#else
8060 val = sd->battle_status.aspd_rate2;
8061#endif
8062 break;
8063 case SP_HP_RECOV_RATE: val = sd->hprecov_rate; break;
8064 case SP_SP_RECOV_RATE: val = sd->sprecov_rate; break;
8065 case SP_CRITICAL_DEF: val = sd->bonus.critical_def; break;
8066 case SP_NEAR_ATK_DEF: val = sd->bonus.near_attack_def_rate; break;
8067 case SP_LONG_ATK_DEF: val = sd->bonus.long_attack_def_rate; break;
8068 case SP_DOUBLE_RATE: val = sd->bonus.double_rate; break;
8069 case SP_DOUBLE_ADD_RATE: val = sd->bonus.double_add_rate; break;
8070 case SP_MATK_RATE: val = sd->matk_rate; break;
8071 case SP_ATK_RATE: val = sd->bonus.atk_rate; break;
8072 case SP_MAGIC_ATK_DEF: val = sd->bonus.magic_def_rate; break;
8073 case SP_MISC_ATK_DEF: val = sd->bonus.misc_def_rate; break;
8074 case SP_PERFECT_HIT_RATE:val = sd->bonus.perfect_hit; break;
8075 case SP_PERFECT_HIT_ADD_RATE: val = sd->bonus.perfect_hit_add; break;
8076 case SP_CRITICAL_RATE: val = sd->critical_rate; break;
8077 case SP_HIT_RATE: val = sd->hit_rate; break;
8078 case SP_FLEE_RATE: val = sd->flee_rate; break;
8079 case SP_FLEE2_RATE: val = sd->flee2_rate; break;
8080 case SP_DEF_RATE: val = sd->def_rate; break;
8081 case SP_DEF2_RATE: val = sd->def2_rate; break;
8082 case SP_MDEF_RATE: val = sd->mdef_rate; break;
8083 case SP_MDEF2_RATE: val = sd->mdef2_rate; break;
8084 case SP_RESTART_FULL_RECOVER: val = sd->special_state.restart_full_recover?1:0; break;
8085 case SP_NO_CASTCANCEL: val = sd->special_state.no_castcancel?1:0; break;
8086 case SP_NO_CASTCANCEL2: val = sd->special_state.no_castcancel2?1:0; break;
8087 case SP_NO_SIZEFIX: val = sd->special_state.no_sizefix?1:0; break;
8088 case SP_NO_MAGIC_DAMAGE: val = sd->special_state.no_magic_damage; break;
8089 case SP_NO_WEAPON_DAMAGE:val = sd->special_state.no_weapon_damage; break;
8090 case SP_NO_MISC_DAMAGE: val = sd->special_state.no_misc_damage; break;
8091 case SP_NO_GEMSTONE: val = sd->special_state.no_gemstone?1:0; break;
8092 case SP_INTRAVISION: val = sd->special_state.intravision?1:0; break;
8093 case SP_NO_KNOCKBACK: val = sd->special_state.no_knockback?1:0; break;
8094 case SP_SPLASH_RANGE: val = sd->bonus.splash_range; break;
8095 case SP_SPLASH_ADD_RANGE:val = sd->bonus.splash_add_range; break;
8096 case SP_SHORT_WEAPON_DAMAGE_RETURN: val = sd->bonus.short_weapon_damage_return; break;
8097 case SP_LONG_WEAPON_DAMAGE_RETURN: val = sd->bonus.long_weapon_damage_return; break;
8098 case SP_MAGIC_DAMAGE_RETURN: val = sd->bonus.magic_damage_return; break;
8099 case SP_PERFECT_HIDE: val = sd->special_state.perfect_hiding?1:0; break;
8100 case SP_UNBREAKABLE: val = sd->bonus.unbreakable; break;
8101 case SP_UNBREAKABLE_WEAPON: val = (sd->bonus.unbreakable_equip&EQP_WEAPON)?1:0; break;
8102 case SP_UNBREAKABLE_ARMOR: val = (sd->bonus.unbreakable_equip&EQP_ARMOR)?1:0; break;
8103 case SP_UNBREAKABLE_HELM: val = (sd->bonus.unbreakable_equip&EQP_HELM)?1:0; break;
8104 case SP_UNBREAKABLE_SHIELD: val = (sd->bonus.unbreakable_equip&EQP_SHIELD)?1:0; break;
8105 case SP_UNBREAKABLE_GARMENT: val = (sd->bonus.unbreakable_equip&EQP_GARMENT)?1:0; break;
8106 case SP_UNBREAKABLE_SHOES: val = (sd->bonus.unbreakable_equip&EQP_SHOES)?1:0; break;
8107 case SP_CLASSCHANGE: val = sd->bonus.classchange; break;
8108 case SP_LONG_ATK_RATE: val = sd->bonus.long_attack_atk_rate; break;
8109 case SP_BREAK_WEAPON_RATE: val = sd->bonus.break_weapon_rate; break;
8110 case SP_BREAK_ARMOR_RATE: val = sd->bonus.break_armor_rate; break;
8111 case SP_ADD_STEAL_RATE: val = sd->bonus.add_steal_rate; break;
8112 case SP_DELAYRATE: val = sd->delayrate; break;
8113 case SP_CRIT_ATK_RATE: val = sd->bonus.crit_atk_rate; break;
8114 case SP_UNSTRIPABLE_WEAPON: val = (sd->bonus.unstripable_equip&EQP_WEAPON)?1:0; break;
8115 case SP_UNSTRIPABLE:
8116 case SP_UNSTRIPABLE_ARMOR:
8117 val = (sd->bonus.unstripable_equip&EQP_ARMOR)?1:0;
8118 break;
8119 case SP_UNSTRIPABLE_HELM: val = (sd->bonus.unstripable_equip&EQP_HELM)?1:0; break;
8120 case SP_UNSTRIPABLE_SHIELD: val = (sd->bonus.unstripable_equip&EQP_SHIELD)?1:0; break;
8121 case SP_SP_GAIN_VALUE: val = sd->bonus.sp_gain_value; break;
8122 case SP_HP_GAIN_VALUE: val = sd->bonus.hp_gain_value; break;
8123 case SP_MAGIC_SP_GAIN_VALUE: val = sd->bonus.magic_sp_gain_value; break;
8124 case SP_MAGIC_HP_GAIN_VALUE: val = sd->bonus.magic_hp_gain_value; break;
8125 case SP_ADD_HEAL_RATE: val = sd->bonus.add_heal_rate; break;
8126 case SP_ADD_HEAL2_RATE: val = sd->bonus.add_heal2_rate; break;
8127 case SP_ADD_ITEM_HEAL_RATE: val = sd->bonus.itemhealrate2; break;
8128 case SP_EMATK: val = sd->bonus.ematk; break;
8129 case SP_FIXCASTRATE: val = sd->bonus.fixcastrate; break;
8130 case SP_ADD_FIXEDCAST: val = sd->bonus.add_fixcast; break;
8131#ifdef RENEWAL_CAST
8132 case SP_VARCASTRATE: val = sd->bonus.varcastrate; break;
8133 case SP_ADD_VARIABLECAST:val = sd->bonus.add_varcast; break;
8134#endif
8135 }
8136
8137 return val;
8138}
8139
8140/*==========================================
8141 * script set pc status registry
8142 *------------------------------------------*/
8143int pc_setparam(struct map_session_data *sd,int type,int val)
8144{
8145 nullpo_ret(sd);
8146
8147 switch(type){
8148 case SP_BASELEVEL:
8149 if (val > pc->maxbaselv(sd)) //Capping to max
8150 val = pc->maxbaselv(sd);
8151 if (val > sd->status.base_level) {
8152 int stat = 0, i;
8153 for (i = 0; i < val - sd->status.base_level; i++)
8154 stat += pc->gets_status_point(sd->status.base_level + i);
8155 sd->status.status_point += stat;
8156 }
8157 sd->status.base_level = val;
8158 sd->status.base_exp = 0;
8159 // clif->updatestatus(sd, SP_BASELEVEL); // Gets updated at the bottom
8160 clif->updatestatus(sd, SP_NEXTBASEEXP);
8161 clif->updatestatus(sd, SP_STATUSPOINT);
8162 clif->updatestatus(sd, SP_BASEEXP);
8163 status_calc_pc(sd, SCO_FORCE);
8164 if(sd->status.party_id)
8165 {
8166 party->send_levelup(sd);
8167 }
8168 break;
8169 case SP_JOBLEVEL:
8170 if (val >= sd->status.job_level) {
8171 if (val > pc->maxjoblv(sd))
8172 val = pc->maxjoblv(sd);
8173 sd->status.skill_point += val - sd->status.job_level;
8174 clif->updatestatus(sd, SP_SKILLPOINT);
8175 }
8176 sd->status.job_level = val;
8177 sd->status.job_exp = 0;
8178 // clif->updatestatus(sd, SP_JOBLEVEL); // Gets updated at the bottom
8179 clif->updatestatus(sd, SP_NEXTJOBEXP);
8180 clif->updatestatus(sd, SP_JOBEXP);
8181 status_calc_pc(sd, SCO_FORCE);
8182 break;
8183 case SP_SKILLPOINT:
8184 sd->status.skill_point = val;
8185 break;
8186 case SP_STATUSPOINT:
8187 sd->status.status_point = val;
8188 break;
8189 case SP_ZENY:
8190 if( val < 0 )
8191 return 0;// can't set negative zeny
8192 logs->zeny(sd, LOG_TYPE_SCRIPT, sd, -(sd->status.zeny - cap_value(val, 0, MAX_ZENY)));
8193 sd->status.zeny = cap_value(val, 0, MAX_ZENY);
8194 break;
8195 case SP_BASEEXP:
8196 if(pc->nextbaseexp(sd) > 0) {
8197 sd->status.base_exp = val;
8198 pc->checkbaselevelup(sd);
8199 }
8200 break;
8201 case SP_JOBEXP:
8202 if(pc->nextjobexp(sd) > 0) {
8203 sd->status.job_exp = val;
8204 pc->checkjoblevelup(sd);
8205 }
8206 break;
8207 case SP_SEX:
8208 sd->status.sex = val ? SEX_MALE : SEX_FEMALE;
8209 break;
8210 case SP_WEIGHT:
8211 sd->weight = val;
8212 break;
8213 case SP_MAXWEIGHT:
8214 sd->max_weight = val;
8215 break;
8216 case SP_HP:
8217 sd->battle_status.hp = cap_value(val, 1, (int)sd->battle_status.max_hp);
8218 break;
8219 case SP_MAXHP:
8220 sd->battle_status.max_hp = cap_value(val, 1, battle_config.max_hp);
8221
8222 if( sd->battle_status.max_hp < sd->battle_status.hp )
8223 {
8224 sd->battle_status.hp = sd->battle_status.max_hp;
8225 clif->updatestatus(sd, SP_HP);
8226 }
8227 break;
8228 case SP_SP:
8229 sd->battle_status.sp = cap_value(val, 0, (int)sd->battle_status.max_sp);
8230 break;
8231 case SP_MAXSP:
8232 sd->battle_status.max_sp = cap_value(val, 1, battle_config.max_sp);
8233
8234 if( sd->battle_status.max_sp < sd->battle_status.sp )
8235 {
8236 sd->battle_status.sp = sd->battle_status.max_sp;
8237 clif->updatestatus(sd, SP_SP);
8238 }
8239 break;
8240 case SP_STR:
8241 sd->status.str = cap_value(val, 1, pc_maxparameter(sd));
8242 break;
8243 case SP_AGI:
8244 sd->status.agi = cap_value(val, 1, pc_maxparameter(sd));
8245 break;
8246 case SP_VIT:
8247 sd->status.vit = cap_value(val, 1, pc_maxparameter(sd));
8248 break;
8249 case SP_INT:
8250 sd->status.int_ = cap_value(val, 1, pc_maxparameter(sd));
8251 break;
8252 case SP_DEX:
8253 sd->status.dex = cap_value(val, 1, pc_maxparameter(sd));
8254 break;
8255 case SP_LUK:
8256 sd->status.luk = cap_value(val, 1, pc_maxparameter(sd));
8257 break;
8258 case SP_KARMA:
8259 sd->status.karma = val;
8260 break;
8261 case SP_MANNER:
8262 sd->status.manner = val;
8263 if( val < 0 )
8264 sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0);
8265 else {
8266 status_change_end(&sd->bl, SC_NOCHAT, INVALID_TIMER);
8267 clif->manner_message(sd, 5);
8268 }
8269 return 1; // status_change_start/status_change_end already sends packets warning the client
8270 case SP_FAME:
8271 sd->status.fame = val;
8272 break;
8273 case SP_KILLERRID:
8274 sd->killerrid = val;
8275 return 1;
8276 case SP_KILLEDRID:
8277 sd->killedrid = val;
8278 return 1;
8279 case SP_SLOTCHANGE:
8280 sd->status.slotchange = val;
8281 return 1;
8282 case SP_CHARRENAME:
8283 sd->status.rename = val;
8284 return 1;
8285 case SP_MOD_EXP:
8286 sd->status.mod_exp = val;
8287 return 1;
8288 case SP_MOD_DROP:
8289 sd->status.mod_drop = val;
8290 return 1;
8291 case SP_MOD_DEATH:
8292 sd->status.mod_death = val;
8293 return 1;
8294 default:
8295 ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type);
8296 return 0;
8297 }
8298 clif->updatestatus(sd,type);
8299
8300 return 1;
8301}
8302
8303/*==========================================
8304 * HP/SP Healing. If flag is passed, the heal type is through clif->heal, otherwise update status.
8305 *------------------------------------------*/
8306void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int type)
8307{
8308 nullpo_retv(sd);
8309 if (type) {
8310 if (hp)
8311 clif->heal(sd->fd,SP_HP,hp);
8312 if (sp)
8313 clif->heal(sd->fd,SP_SP,sp);
8314 } else {
8315 if(hp)
8316 clif->updatestatus(sd,SP_HP);
8317 if(sp)
8318 clif->updatestatus(sd,SP_SP);
8319 }
8320 return;
8321}
8322
8323/*==========================================
8324 * HP/SP Recovery
8325 * Heal player hp and/or sp linearly.
8326 * Calculate bonus by status.
8327 *------------------------------------------*/
8328int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
8329{
8330 int bonus, tmp;
8331
8332 nullpo_ret(sd);
8333 if(hp) {
8334 int i;
8335 bonus = 100 + (sd->battle_status.vit<<1)
8336 + pc->checkskill(sd,SM_RECOVERY)*10
8337 + pc->checkskill(sd,AM_LEARNINGPOTION)*5;
8338 // A potion produced by an Alchemist in the Fame Top 10 gets +50% effect [DracoRPG]
8339 if (script->potion_flag > 1)
8340 bonus += bonus*(script->potion_flag-1)*50/100;
8341 //All item bonuses.
8342 bonus += sd->bonus.itemhealrate2;
8343 //Individual item bonuses.
8344 for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) {
8345 struct item_data *it = itemdb->exists(sd->itemhealrate[i].nameid);
8346 if (sd->itemhealrate[i].nameid == itemid || (it && it->group && itemdb->in_group(it->group,itemid))) {
8347 bonus += bonus*sd->itemhealrate[i].rate/100;
8348 break;
8349 }
8350 }
8351
8352 tmp = hp*bonus/100;
8353 if(bonus != 100 && tmp > hp)
8354 hp = tmp;
8355
8356 // Recovery Potion
8357 if( sd->sc.data[SC_HEALPLUS] )
8358 hp += (int)(hp * sd->sc.data[SC_HEALPLUS]->val1/100.);
8359
8360 // 2014 Halloween Event : Pumpkin Bonus
8361 if ( sd->sc.data[SC_MTF_PUMPKIN] && itemid == ITEMID_PUMPKIN )
8362 hp += (int)(hp * sd->sc.data[SC_MTF_PUMPKIN]->val1/100);
8363 }
8364 if(sp) {
8365 bonus = 100 + (sd->battle_status.int_<<1)
8366 + pc->checkskill(sd,MG_SRECOVERY)*10
8367 + pc->checkskill(sd,AM_LEARNINGPOTION)*5;
8368 if (script->potion_flag > 1)
8369 bonus += bonus*(script->potion_flag-1)*50/100;
8370
8371 tmp = sp*bonus/100;
8372 if(bonus != 100 && tmp > sp)
8373 sp = tmp;
8374 }
8375 if( sd->sc.count ) {
8376 if ( sd->sc.data[SC_CRITICALWOUND] ) {
8377 hp -= hp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
8378 sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
8379 }
8380
8381 if( sd->sc.data[SC_VITALITYACTIVATION] ){
8382 hp += hp / 2; // 1.5 times
8383 sp -= sp / 2;
8384 }
8385
8386 if ( sd->sc.data[SC_DEATHHURT] ) {
8387 hp -= hp * 20 / 100;
8388 sp -= sp * 20 / 100;
8389 }
8390
8391 if( sd->sc.data[SC_WATER_INSIGNIA] && sd->sc.data[SC_WATER_INSIGNIA]->val1 == 2 ) {
8392 hp += hp / 10;
8393 sp += sp / 10;
8394 }
8395#ifdef RENEWAL
8396 if( sd->sc.data[SC_EXTREMITYFIST2] )
8397 sp = 0;
8398#endif
8399 }
8400
8401 return status->heal(&sd->bl, hp, sp, 1);
8402}
8403
8404/*==========================================
8405 * HP/SP Recovery
8406 * Heal player hp nad/or sp by rate
8407 *------------------------------------------*/
8408int pc_percentheal(struct map_session_data *sd,int hp,int sp)
8409{
8410 nullpo_ret(sd);
8411
8412 if(hp > 100) hp = 100;
8413 else
8414 if(hp <-100) hp =-100;
8415
8416 if(sp > 100) sp = 100;
8417 else
8418 if(sp <-100) sp =-100;
8419
8420 if(hp >= 0 && sp >= 0) //Heal
8421 return status_percent_heal(&sd->bl, hp, sp);
8422
8423 if(hp <= 0 && sp <= 0) //Damage (negative rates indicate % of max rather than current), and only kill target IF the specified amount is 100%
8424 return status_percent_damage(NULL, &sd->bl, hp, sp, hp==-100);
8425
8426 //Crossed signs
8427 if(hp) {
8428 if(hp > 0)
8429 status_percent_heal(&sd->bl, hp, 0);
8430 else
8431 status_percent_damage(NULL, &sd->bl, hp, 0, hp==-100);
8432 }
8433
8434 if(sp) {
8435 if(sp > 0)
8436 status_percent_heal(&sd->bl, 0, sp);
8437 else
8438 status_percent_damage(NULL, &sd->bl, 0, sp, false);
8439 }
8440 return 0;
8441}
8442
8443int jobchange_killclone(struct block_list *bl, va_list ap)
8444{
8445 struct mob_data *md = NULL;
8446 int flag = va_arg(ap, int);
8447
8448 nullpo_ret(bl);
8449 Assert_ret(bl->type == BL_MOB);
8450 md = BL_UCAST(BL_MOB, bl);
8451
8452 if (md->master_id && md->special_state.clone && md->master_id == flag)
8453 status_kill(&md->bl);
8454 return 1;
8455}
8456
8457/*==========================================
8458 * Called when player changes job
8459 * Rewrote to make it tidider [Celest]
8460 *------------------------------------------*/
8461int pc_jobchange(struct map_session_data *sd,int job, int upper)
8462{
8463 int i, fame_flag=0;
8464 int b_class, idx = 0;
8465
8466 nullpo_ret(sd);
8467
8468 if (job < 0)
8469 return 1;
8470
8471 //Normalize job.
8472 b_class = pc->jobid2mapid(job);
8473 if (b_class == -1)
8474 return 1;
8475 switch (upper) {
8476 case 1:
8477 b_class|= JOBL_UPPER;
8478 break;
8479 case 2:
8480 b_class|= JOBL_BABY;
8481 break;
8482 }
8483 //This will automatically adjust bard/dancer classes to the correct gender
8484 //That is, if you try to jobchange into dancer, it will turn you to bard.
8485 job = pc->mapid2jobid(b_class, sd->status.sex);
8486 if (job == -1)
8487 return 1;
8488
8489 if ((unsigned short)b_class == sd->class_)
8490 return 1; //Nothing to change.
8491
8492 // changing from 1st to 2nd job
8493 if ((b_class&JOBL_2) && !(sd->class_&JOBL_2) && (b_class&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) {
8494 sd->change_level_2nd = sd->status.job_level;
8495 pc_setglobalreg(sd, script->add_str("jobchange_level"), sd->change_level_2nd);
8496 }
8497 // changing from 2nd to 3rd job
8498 else if((b_class&JOBL_THIRD) && !(sd->class_&JOBL_THIRD)) {
8499 sd->change_level_3rd = sd->status.job_level;
8500 pc_setglobalreg(sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd);
8501 }
8502
8503 if(sd->cloneskill_id) {
8504 idx = skill->get_index(sd->cloneskill_id);
8505 if( sd->status.skill[idx].flag == SKILL_FLAG_PLAGIARIZED ) {
8506 sd->status.skill[idx].id = 0;
8507 sd->status.skill[idx].lv = 0;
8508 sd->status.skill[idx].flag = 0;
8509 clif->deleteskill(sd,sd->cloneskill_id);
8510 }
8511 sd->cloneskill_id = 0;
8512 pc_setglobalreg(sd, script->add_str("CLONE_SKILL"), 0);
8513 pc_setglobalreg(sd, script->add_str("CLONE_SKILL_LV"), 0);
8514 }
8515
8516 if(sd->reproduceskill_id) {
8517 idx = skill->get_index(sd->reproduceskill_id);
8518 if( sd->status.skill[idx].flag == SKILL_FLAG_PLAGIARIZED ) {
8519 sd->status.skill[idx].id = 0;
8520 sd->status.skill[idx].lv = 0;
8521 sd->status.skill[idx].flag = 0;
8522 clif->deleteskill(sd,sd->reproduceskill_id);
8523 }
8524 sd->reproduceskill_id = 0;
8525 pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL"),0);
8526 pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL_LV"),0);
8527 }
8528
8529 if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree.
8530 const int class_ = pc->class2idx(sd->status.class_);
8531 short id;
8532 for(i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[class_][i].id) > 0; i++) {
8533 //Remove status specific to your current tree skills.
8534 enum sc_type sc = status->skill2sc(id);
8535 if (sc > SC_COMMON_MAX && sd->sc.data[sc])
8536 status_change_end(&sd->bl, sc, INVALID_TIMER);
8537 }
8538 }
8539
8540 if( (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && (b_class&MAPID_UPPERMASK) != MAPID_STAR_GLADIATOR) {
8541 /* going off star glad lineage, reset feel to not store no-longer-used vars in the database */
8542 pc->resetfeel(sd);
8543 }
8544
8545 sd->status.class_ = job;
8546 fame_flag = pc->famerank(sd->status.char_id,sd->class_&MAPID_UPPERMASK);
8547 sd->class_ = (unsigned short)b_class;
8548 sd->status.job_level=1;
8549 sd->status.job_exp=0;
8550
8551 if (sd->status.base_level > pc->maxbaselv(sd)) {
8552 sd->status.base_level = pc->maxbaselv(sd);
8553 sd->status.base_exp=0;
8554 pc->resetstate(sd);
8555 clif->updatestatus(sd,SP_STATUSPOINT);
8556 clif->updatestatus(sd,SP_BASELEVEL);
8557 clif->updatestatus(sd,SP_BASEEXP);
8558 clif->updatestatus(sd,SP_NEXTBASEEXP);
8559 }
8560
8561 clif->updatestatus(sd,SP_JOBLEVEL);
8562 clif->updatestatus(sd,SP_JOBEXP);
8563 clif->updatestatus(sd,SP_NEXTJOBEXP);
8564
8565 for(i=0;i<EQI_MAX;i++) {
8566 if(sd->equip_index[i] >= 0)
8567 if(!pc->isequip(sd,sd->equip_index[i]))
8568 pc->unequipitem(sd,sd->equip_index[i], PCUNEQUIPITEM_FORCE); // unequip invalid item for class
8569 }
8570
8571 //Change look, if disguised, you need to undisguise
8572 //to correctly calculate new job sprite without
8573 if (sd->disguise != -1)
8574 pc->disguise(sd, -1);
8575
8576 status->set_viewdata(&sd->bl, job);
8577 clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); // move sprite update to prevent client crashes with incompatible equipment [Valaris]
8578 if(sd->vd.cloth_color)
8579 clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
8580 if (sd->vd.body_style)
8581 clif->changelook(&sd->bl,LOOK_BODY2,sd->vd.body_style);
8582
8583 //Update skill tree.
8584 pc->calc_skilltree(sd);
8585 clif->skillinfoblock(sd);
8586
8587 if (sd->ed)
8588 elemental->delete(sd->ed, 0);
8589 if (sd->state.vending)
8590 vending->close(sd);
8591
8592 map->foreachinmap(pc->jobchange_killclone, sd->bl.m, BL_MOB, sd->bl.id);
8593
8594 //Remove peco/cart/falcon
8595 i = sd->sc.option;
8596 if( i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) )
8597 i&=~OPTION_RIDING;
8598 if( i&OPTION_FALCON && !pc->checkskill(sd, HT_FALCON) )
8599 i&=~OPTION_FALCON;
8600 if( i&OPTION_DRAGON && !pc->checkskill(sd,RK_DRAGONTRAINING) )
8601 i&=~OPTION_DRAGON;
8602 if( i&OPTION_WUGRIDER && !pc->checkskill(sd,RA_WUGMASTERY) )
8603 i&=~OPTION_WUGRIDER;
8604 if( i&OPTION_WUG && !pc->checkskill(sd,RA_WUGMASTERY) )
8605 i&=~OPTION_WUG;
8606 if( i&OPTION_MADOGEAR ) //You do not need a skill for this.
8607 i&=~OPTION_MADOGEAR;
8608#ifndef NEW_CARTS
8609 if( i&OPTION_CART && !pc->checkskill(sd, MC_PUSHCART) )
8610 i&=~OPTION_CART;
8611#else
8612 if( sd->sc.data[SC_PUSH_CART] && !pc->checkskill(sd, MC_PUSHCART) )
8613 pc->setcart(sd, 0);
8614#endif
8615 if(i != sd->sc.option)
8616 pc->setoption(sd, i);
8617
8618 if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN))
8619 homun->vaporize(sd, HOM_ST_REST);
8620
8621 if(sd->status.manner < 0)
8622 clif->changestatus(sd,SP_MANNER,sd->status.manner);
8623
8624 status_calc_pc(sd,SCO_FORCE);
8625 pc->checkallowskill(sd);
8626 pc->equiplookall(sd);
8627
8628 //if you were previously famous, not anymore.
8629 if (fame_flag) {
8630 chrif->save(sd,0);
8631 chrif->buildfamelist();
8632 } else if (sd->status.fame > 0) {
8633 //It may be that now they are famous?
8634 switch (sd->class_&MAPID_UPPERMASK) {
8635 case MAPID_BLACKSMITH:
8636 case MAPID_ALCHEMIST:
8637 case MAPID_TAEKWON:
8638 chrif->save(sd,0);
8639 chrif->buildfamelist();
8640 break;
8641 }
8642 }
8643
8644 return 0;
8645}
8646
8647/*==========================================
8648 * Tell client player sd has change equipement
8649 *------------------------------------------*/
8650int pc_equiplookall(struct map_session_data *sd)
8651{
8652 nullpo_ret(sd);
8653
8654 clif->changelook(&sd->bl,LOOK_WEAPON,0);
8655 clif->changelook(&sd->bl,LOOK_SHOES,0);
8656 clif->changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
8657 clif->changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
8658 clif->changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
8659 clif->changelook(&sd->bl,LOOK_ROBE, sd->status.robe);
8660
8661 return 0;
8662}
8663
8664/*==========================================
8665 * Tell client player sd has change look (hair,equip...)
8666 *------------------------------------------*/
8667int pc_changelook(struct map_session_data *sd,int type,int val)
8668{
8669 nullpo_ret(sd);
8670
8671 switch(type){
8672 case LOOK_BASE:
8673 status->set_viewdata(&sd->bl, val);
8674 clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_);
8675 clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
8676 if (sd->vd.cloth_color)
8677 clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
8678 if (sd->vd.body_style)
8679 clif->changelook(&sd->bl,LOOK_BODY2,sd->vd.body_style);
8680 clif->skillinfoblock(sd);
8681 return 0;
8682 break;
8683 case LOOK_HAIR: //Use the battle_config limits! [Skotlex]
8684 val = cap_value(val, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
8685
8686 if (sd->status.hair != val) {
8687 sd->status.hair=val;
8688 if (sd->status.guild_id) //Update Guild Window. [Skotlex]
8689 intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id,
8690 GMI_HAIR,&sd->status.hair,sizeof(sd->status.hair));
8691 }
8692 break;
8693 case LOOK_WEAPON:
8694 sd->status.weapon=val;
8695 break;
8696 case LOOK_HEAD_BOTTOM:
8697 sd->status.head_bottom=val;
8698 break;
8699 case LOOK_HEAD_TOP:
8700 sd->status.head_top=val;
8701 break;
8702 case LOOK_HEAD_MID:
8703 sd->status.head_mid=val;
8704 break;
8705 case LOOK_HAIR_COLOR: //Use the battle_config limits! [Skotlex]
8706 val = cap_value(val, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
8707
8708 if (sd->status.hair_color != val) {
8709 sd->status.hair_color=val;
8710 if (sd->status.guild_id) //Update Guild Window. [Skotlex]
8711 intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id,
8712 GMI_HAIR_COLOR,&sd->status.hair_color,sizeof(sd->status.hair_color));
8713 }
8714 break;
8715 case LOOK_CLOTHES_COLOR: //Use the battle_config limits! [Skotlex]
8716 val = cap_value(val, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
8717
8718 sd->status.clothes_color=val;
8719 break;
8720 case LOOK_SHIELD:
8721 sd->status.shield=val;
8722 break;
8723 case LOOK_SHOES:
8724 break;
8725 case LOOK_ROBE:
8726 sd->status.robe = val;
8727 break;
8728 case LOOK_BODY2:
8729 val = cap_value(val, MIN_BODY_STYLE, MAX_BODY_STYLE);
8730 sd->status.body=val;
8731 break;
8732 }
8733 clif->changelook(&sd->bl,type,val);
8734 return 0;
8735}
8736
8737/*==========================================
8738 * Give an option (type) to player (sd) and display it to client
8739 *------------------------------------------*/
8740int pc_setoption(struct map_session_data *sd,int type)
8741{
8742 int p_type, new_look=0;
8743 nullpo_ret(sd);
8744 p_type = sd->sc.option;
8745
8746 //Option has to be changed client-side before the class sprite or it won't always work (eg: Wedding sprite) [Skotlex]
8747 sd->sc.option=type;
8748 clif->changeoption(&sd->bl);
8749
8750 if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc->checkskill(sd,RK_DRAGONTRAINING) > 0) ) {
8751 // Mounting
8752 clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_RIDING, 0, 0, 0);
8753 status_calc_pc(sd,SCO_NONE);
8754 } else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON) ) {
8755 // Dismount
8756 clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_RIDING);
8757 status_calc_pc(sd,SCO_NONE);
8758 }
8759
8760#ifndef NEW_CARTS
8761 if( type&OPTION_CART && !( p_type&OPTION_CART ) ) { //Cart On
8762 clif->cartlist(sd);
8763 clif->updatestatus(sd, SP_CARTINFO);
8764 if(pc->checkskill(sd, MC_PUSHCART) < 10)
8765 status_calc_pc(sd,SCO_NONE); //Apply speed penalty.
8766 } else if( !( type&OPTION_CART ) && p_type&OPTION_CART ){ //Cart Off
8767 clif->clearcart(sd->fd);
8768 if(pc->checkskill(sd, MC_PUSHCART) < 10)
8769 status_calc_pc(sd,SCO_NONE); //Remove speed penalty.
8770 if ( sd->equip_index[EQI_AMMO] > 0 )
8771 pc->unequipitem(sd, sd->equip_index[EQI_AMMO], PCUNEQUIPITEM_FORCE);
8772 }
8773#endif
8774
8775 if (type&OPTION_FALCON && !(p_type&OPTION_FALCON)) //Falcon ON
8776 clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_FALCON, 0, 0, 0);
8777 else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF
8778 clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_FALCON);
8779
8780 if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting
8781 clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0);
8782 status_calc_pc(sd,SCO_NONE);
8783 } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount
8784 clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER);
8785 status_calc_pc(sd,SCO_NONE);
8786 }
8787
8788 if( (type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR))
8789 || (!(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR) ) {
8790 int i;
8791 status_calc_pc(sd, SCO_NONE);
8792
8793 // End all SCs that can be reset when mado is taken off
8794 for( i = 0; i < SC_MAX; i++ ) {
8795 if ( !sd->sc.data[i] || !status->get_sc_type(i) )
8796 continue;
8797 if ( status->get_sc_type(i)&SC_MADO_NO_RESET )
8798 continue;
8799 switch (i) {
8800 case SC_BERSERK:
8801 case SC_SATURDAY_NIGHT_FEVER:
8802 sd->sc.data[i]->val2 = 0;
8803 break;
8804 }
8805 status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER);
8806 }
8807 if ( sd->equip_index[EQI_AMMO] > 0 )
8808 pc->unequipitem(sd, sd->equip_index[EQI_AMMO], PCUNEQUIPITEM_FORCE);
8809 }
8810
8811 if (type&OPTION_FLYING && !(p_type&OPTION_FLYING))
8812 new_look = JOB_STAR_GLADIATOR2;
8813 else if (!(type&OPTION_FLYING) && p_type&OPTION_FLYING)
8814 new_look = -1;
8815
8816 if (sd->disguise != -1 || !new_look)
8817 return 0; //Disguises break sprite changes
8818
8819 if (new_look < 0) { //Restore normal look.
8820 status->set_viewdata(&sd->bl, sd->status.class_);
8821 new_look = sd->vd.class_;
8822 }
8823
8824 pc_stop_attack(sd); //Stop attacking on new view change (to prevent wedding/santa attacks.
8825 clif->changelook(&sd->bl,LOOK_BASE,new_look);
8826 if (sd->vd.cloth_color)
8827 clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
8828 if( sd->vd.body_style )
8829 clif->changelook(&sd->bl,LOOK_BODY2,sd->vd.body_style);
8830 clif->skillinfoblock(sd); // Skill list needs to be updated after base change.
8831
8832 return 0;
8833}
8834
8835/*==========================================
8836 * Give player a cart
8837 *------------------------------------------*/
8838int pc_setcart(struct map_session_data *sd,int type) {
8839#ifndef NEW_CARTS
8840 int cart[6] = {OPTION_NOTHING,OPTION_CART1,OPTION_CART2,OPTION_CART3,OPTION_CART4,OPTION_CART5};
8841 int option;
8842#endif
8843 nullpo_ret(sd);
8844
8845 if( type < 0 || type > MAX_CARTS )
8846 return 1;// Never trust the values sent by the client! [Skotlex]
8847
8848 if( pc->checkskill(sd,MC_PUSHCART) <= 0 && type != 0 )
8849 return 1;// Push cart is required
8850
8851 if( type == 0 && pc_iscarton(sd) )
8852 status_change_end(&sd->bl,SC_GN_CARTBOOST,INVALID_TIMER);
8853
8854#ifdef NEW_CARTS
8855
8856 switch( type ) {
8857 case 0:
8858 if( !sd->sc.data[SC_PUSH_CART] )
8859 return 0;
8860 status_change_end(&sd->bl,SC_PUSH_CART,INVALID_TIMER);
8861 clif->clearcart(sd->fd);
8862 clif->updatestatus(sd, SP_CARTINFO);
8863 if ( sd->equip_index[EQI_AMMO] > 0 )
8864 pc->unequipitem(sd, sd->equip_index[EQI_AMMO], PCUNEQUIPITEM_FORCE);
8865 break;
8866 default:/* everything else is an allowed ID so we can move on */
8867 if( !sd->sc.data[SC_PUSH_CART] ) /* first time, so fill cart data */
8868 clif->cartlist(sd);
8869 clif->updatestatus(sd, SP_CARTINFO);
8870 sc_start(NULL,&sd->bl, SC_PUSH_CART, 100, type, 0);
8871 clif->sc_load(&sd->bl, sd->bl.id, AREA, SI_ON_PUSH_CART, type, 0, 0);
8872 if( sd->sc.data[SC_PUSH_CART] )/* forcefully update */
8873 sd->sc.data[SC_PUSH_CART]->val1 = type;
8874 break;
8875 }
8876
8877 if(pc->checkskill(sd, MC_PUSHCART) < 10)
8878 status_calc_pc(sd,SCO_NONE); //Recalc speed penalty.
8879#else
8880 // Update option
8881 option = sd->sc.option;
8882 option &= ~OPTION_CART;// clear cart bits
8883 option |= cart[type]; // set cart
8884 pc->setoption(sd, option);
8885#endif
8886
8887 return 0;
8888}
8889
8890/* FIXME: These setter methods are inconsistent in their class/skill checks.
8891 * They should be changed so that they all either do or skip the checks.*/
8892
8893/**
8894 * Gives/removes a falcon.
8895 *
8896 * The target player needs the required skills in order to obtain a falcon.
8897 *
8898 * @param sd Target player.
8899 * @param flag New state.
8900 **/
8901void pc_setfalcon(struct map_session_data *sd, bool flag)
8902{
8903 nullpo_retv(sd);
8904 if (flag) {
8905 if (pc->checkskill(sd,HT_FALCON) > 0) // add falcon if he have the skill
8906 pc->setoption(sd,sd->sc.option|OPTION_FALCON);
8907 } else if (pc_isfalcon(sd)) {
8908 pc->setoption(sd,sd->sc.option&~OPTION_FALCON); // remove falcon
8909 }
8910}
8911
8912/**
8913 * Mounts/dismounts a Peco or Gryphon.
8914 *
8915 * The target player needs the required skills in order to mount a peco.
8916 *
8917 * @param sd Target player.
8918 * @param flag New state.
8919 **/
8920void pc_setridingpeco(struct map_session_data *sd, bool flag)
8921{
8922 nullpo_retv(sd);
8923 if (flag) {
8924 if (pc->checkskill(sd, KN_RIDING))
8925 pc->setoption(sd, sd->sc.option|OPTION_RIDING);
8926 } else if (pc_isridingpeco(sd)) {
8927 pc->setoption(sd, sd->sc.option&~OPTION_RIDING);
8928 }
8929}
8930
8931/**
8932 * Gives/removes a Mado Gear.
8933 *
8934 * The target player needs to be the correct class in order to obtain a mado gear.
8935 *
8936 * @param sd Target player.
8937 * @param flag New state.
8938 **/
8939void pc_setmadogear(struct map_session_data *sd, bool flag)
8940{
8941 nullpo_retv(sd);
8942 if (flag) {
8943 if ((sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC)
8944 pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR);
8945 } else if (pc_ismadogear(sd)) {
8946 pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
8947 }
8948}
8949
8950/**
8951 * Mounts/dismounts a dragon.
8952 *
8953 * The target player needs the required skills in order to mount a dragon.
8954 *
8955 * @param sd Target player.
8956 * @param type New state. This must be a valid OPTION_DRAGON* or 0.
8957 **/
8958void pc_setridingdragon(struct map_session_data *sd, unsigned int type)
8959{
8960 nullpo_retv(sd);
8961 if (type&OPTION_DRAGON) {
8962 // Ensure only one dragon is set at a time.
8963 if (type&OPTION_DRAGON1)
8964 type = OPTION_DRAGON1;
8965 else if (type&OPTION_DRAGON2)
8966 type = OPTION_DRAGON2;
8967 else if (type&OPTION_DRAGON3)
8968 type = OPTION_DRAGON3;
8969 else if (type&OPTION_DRAGON4)
8970 type = OPTION_DRAGON4;
8971 else if (type&OPTION_DRAGON5)
8972 type = OPTION_DRAGON5;
8973 else
8974 type = OPTION_DRAGON1;
8975
8976 if (pc->checkskill(sd, RK_DRAGONTRAINING))
8977 pc->setoption(sd, (sd->sc.option&~OPTION_DRAGON)|type);
8978 } else if (pc_isridingdragon(sd)) {
8979 pc->setoption(sd,sd->sc.option&~OPTION_DRAGON); // remove dragon
8980 }
8981}
8982
8983/**
8984 * Mounts/dismounts a wug.
8985 *
8986 * The target player needs the required skills in order to mount a wug.
8987 *
8988 * @param sd Target player.
8989 * @param flag New state.
8990 **/
8991void pc_setridingwug(struct map_session_data *sd, bool flag)
8992{
8993 nullpo_retv(sd);
8994 if (flag) {
8995 if (pc->checkskill(sd, RA_WUGRIDER) > 0)
8996 pc->setoption(sd,sd->sc.option|OPTION_WUGRIDER);
8997 } else if (pc_isridingwug(sd)) {
8998 pc->setoption(sd,sd->sc.option&~OPTION_WUGRIDER); // remove wug
8999 }
9000}
9001
9002/**
9003 * Determines whether a player can attack based on status changes
9004 * Why not use status_check_skilluse?
9005 * "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack."
9006 * Even ground-based attacks should be blocked by these statuses
9007 * Called from unit_attack and unit_attack_timer_sub
9008 * @retval true Can attack
9009 **/
9010bool pc_can_attack( struct map_session_data *sd, int target_id ) {
9011 nullpo_retr(false, sd);
9012
9013 if( sd->sc.data[SC_BASILICA] ||
9014 sd->sc.data[SC__SHADOWFORM] ||
9015 sd->sc.data[SC__MANHOLE] ||
9016 sd->sc.data[SC_CURSEDCIRCLE_ATKER] ||
9017 sd->sc.data[SC_CURSEDCIRCLE_TARGET] ||
9018 sd->sc.data[SC_COLD] ||
9019 sd->sc.data[SC_ALL_RIDING] || // The client doesn't let you, this is to make cheat-safe
9020 sd->sc.data[SC_TRICKDEAD] ||
9021 (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) ||
9022 sd->sc.data[SC_BLADESTOP] ||
9023 sd->sc.data[SC_DEEP_SLEEP] ||
9024 sd->sc.data[SC_FALLENEMPIRE] )
9025 return false;
9026
9027 return true;
9028}
9029
9030/**
9031 * Determines whether a player can talk/whisper based on status changes
9032 * Called from clif_parse_GlobalMessage and clif_parse_WisMessage
9033 * @retval true Can talk
9034 **/
9035bool pc_can_talk( struct map_session_data *sd ) {
9036 nullpo_retr(false, sd);
9037
9038 if( sd->sc.data[SC_BERSERK] ||
9039 (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) ||
9040 pc_ismuted(&sd->sc, MANNER_NOCHAT) )
9041 return false;
9042
9043 return true;
9044}
9045
9046/*==========================================
9047 * Check if player can drop an item
9048 *------------------------------------------*/
9049int pc_candrop(struct map_session_data *sd, struct item *item)
9050{
9051 if( item && (item->expire_time || (item->bound && !pc_can_give_bound_items(sd))) )
9052 return 0;
9053 if( !pc_can_give_items(sd) ) //check if this GM level can drop items
9054 return 0;
9055 return (itemdb_isdropable(item, pc_get_group_level(sd)));
9056}
9057/**
9058 * For '@type' variables (temporary numeric char reg)
9059 **/
9060int pc_readreg(struct map_session_data* sd, int64 reg) {
9061 nullpo_ret(sd);
9062 return i64db_iget(sd->regs.vars, reg);
9063}
9064/**
9065 * For '@type' variables (temporary numeric char reg)
9066 **/
9067void pc_setreg(struct map_session_data* sd, int64 reg, int val) {
9068 unsigned int index = script_getvaridx(reg);
9069
9070 nullpo_retv(sd);
9071 if( val ) {
9072 i64db_iput(sd->regs.vars, reg, val);
9073 if( index )
9074 script->array_update(&sd->regs, reg, false);
9075 } else {
9076 i64db_remove(sd->regs.vars, reg);
9077 if( index )
9078 script->array_update(&sd->regs, reg, true);
9079 }
9080}
9081
9082/**
9083 * For '@type$' variables (temporary string char reg)
9084 **/
9085char* pc_readregstr(struct map_session_data* sd, int64 reg) {
9086 struct script_reg_str *p = NULL;
9087
9088 nullpo_retr(NULL, sd);
9089 p = i64db_get(sd->regs.vars, reg);
9090
9091 return p ? p->value : NULL;
9092}
9093/**
9094 * For '@type$' variables (temporary string char reg)
9095 **/
9096void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) {
9097 struct script_reg_str *p = NULL;
9098 unsigned int index = script_getvaridx(reg);
9099 struct DBData prev;
9100
9101 nullpo_retv(sd);
9102 nullpo_retv(str);
9103 if( str[0] ) {
9104 p = ers_alloc(pc->str_reg_ers, struct script_reg_str);
9105
9106 p->value = aStrdup(str);
9107 p->flag.type = 1;
9108
9109 if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) {
9110 p = DB->data2ptr(&prev);
9111 if( p->value )
9112 aFree(p->value);
9113 ers_free(pc->str_reg_ers, p);
9114 } else {
9115 if( index )
9116 script->array_update(&sd->regs, reg, false);
9117 }
9118 } else {
9119 if( sd->regs.vars->remove(sd->regs.vars, DB->i642key(reg), &prev) ) {
9120 p = DB->data2ptr(&prev);
9121 if( p->value )
9122 aFree(p->value);
9123 ers_free(pc->str_reg_ers, p);
9124 if( index )
9125 script->array_update(&sd->regs, reg, true);
9126 }
9127 }
9128}
9129/**
9130 * Serves the following variable types:
9131 * - 'type' (permanent nuneric char reg)
9132 * - '#type' (permanent numeric account reg)
9133 * - '##type' (permanent numeric account reg2)
9134 **/
9135int pc_readregistry(struct map_session_data *sd, int64 reg) {
9136 struct script_reg_num *p = NULL;
9137
9138 nullpo_ret(sd);
9139 if (!sd->vars_ok) {
9140 ShowError("pc_readregistry: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg)));
9141 //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again.
9142 //intif->request_registry(sd,type==3?4:type);
9143 sockt->eof(sd->fd);
9144 return 0;
9145 }
9146
9147 p = i64db_get(sd->regs.vars, reg);
9148
9149 return p ? p->value : 0;
9150}
9151/**
9152 * Serves the following variable types:
9153 * - 'type$' (permanent str char reg)
9154 * - '#type$' (permanent str account reg)
9155 * - '##type$' (permanent str account reg2)
9156 **/
9157char* pc_readregistry_str(struct map_session_data *sd, int64 reg) {
9158 struct script_reg_str *p = NULL;
9159
9160 nullpo_retr(NULL, sd);
9161 if (!sd->vars_ok) {
9162 ShowError("pc_readregistry_str: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg)));
9163 //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again.
9164 //intif->request_registry(sd,type==3?4:type);
9165 sockt->eof(sd->fd);
9166 return NULL;
9167 }
9168
9169 p = i64db_get(sd->regs.vars, reg);
9170
9171 return p ? p->value : NULL;
9172}
9173/**
9174 * Serves the following variable types:
9175 * - 'type' (permanent nuneric char reg)
9176 * - '#type' (permanent numeric account reg)
9177 * - '##type' (permanent numeric account reg2)
9178 **/
9179int pc_setregistry(struct map_session_data *sd, int64 reg, int val) {
9180 struct script_reg_num *p = NULL;
9181 const char *regname = script->get_str( script_getvarid(reg) );
9182 unsigned int index = script_getvaridx(reg);
9183
9184 nullpo_ret(sd);
9185 /* SAAD! those things should be stored elsewhere e.g. char ones in char table, the cash ones in account_data table! */
9186 switch( regname[0] ) {
9187 default: //Char reg
9188 if( !strcmp(regname,"PC_DIE_COUNTER") && sd->die_counter != val ) {
9189 int i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE);
9190 sd->die_counter = val;
9191 if( i )
9192 status_calc_pc(sd,SCO_NONE); // Lost the bonus.
9193 } else if( !strcmp(regname,"COOK_MASTERY") && sd->cook_mastery != val ) {
9194 val = cap_value(val, 0, 1999);
9195 sd->cook_mastery = val;
9196 }
9197 break;
9198 case '#':
9199 if( !strcmp(regname,"#CASHPOINTS") && sd->cashPoints != val ) {
9200 val = cap_value(val, 0, MAX_ZENY);
9201 sd->cashPoints = val;
9202 } else if( !strcmp(regname,"#KAFRAPOINTS") && sd->kafraPoints != val ) {
9203 val = cap_value(val, 0, MAX_ZENY);
9204 sd->kafraPoints = val;
9205 }
9206 break;
9207 }
9208
9209 if ( !pc->reg_load && !sd->vars_ok ) {
9210 ShowError("pc_setregistry : refusing to set %s until vars are received.\n", regname);
9211 return 0;
9212 }
9213
9214 if( (p = i64db_get(sd->regs.vars, reg) ) ) {
9215 if( val ) {
9216 if( !p->value && index ) /* its a entry that was deleted, so we reset array */
9217 script->array_update(&sd->regs, reg, false);
9218 p->value = val;
9219 } else {
9220 p->value = 0;
9221 if( index )
9222 script->array_update(&sd->regs, reg, true);
9223 }
9224 if( !pc->reg_load )
9225 p->flag.update = 1;/* either way, it will require either delete or replace */
9226 } else if( val ) {
9227 struct DBData prev;
9228
9229 if( index )
9230 script->array_update(&sd->regs, reg, false);
9231
9232 p = ers_alloc(pc->num_reg_ers, struct script_reg_num);
9233
9234 p->value = val;
9235 if( !pc->reg_load )
9236 p->flag.update = 1;
9237
9238 if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) {
9239 p = DB->data2ptr(&prev);
9240 ers_free(pc->num_reg_ers, p);
9241 }
9242 }
9243
9244 if( !pc->reg_load && p )
9245 sd->vars_dirty = true;
9246
9247 return 1;
9248}
9249/**
9250 * Serves the following variable types:
9251 * - 'type$' (permanent str char reg)
9252 * - '#type$' (permanent str account reg)
9253 * - '##type$' (permanent str account reg2)
9254 **/
9255int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) {
9256 struct script_reg_str *p = NULL;
9257 const char *regname = script->get_str( script_getvarid(reg) );
9258 unsigned int index = script_getvaridx(reg);
9259
9260 nullpo_ret(sd);
9261 nullpo_ret(val);
9262 if ( !pc->reg_load && !sd->vars_ok ) {
9263 ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname);
9264 return 0;
9265 }
9266
9267 if( (p = i64db_get(sd->regs.vars, reg) ) ) {
9268 if( val[0] ) {
9269 if( p->value )
9270 aFree(p->value);
9271 else if ( index ) /* a entry that was deleted, so we reset */
9272 script->array_update(&sd->regs, reg, false);
9273 p->value = aStrdup(val);
9274 } else {
9275 p->value = NULL;
9276 if( index )
9277 script->array_update(&sd->regs, reg, true);
9278 }
9279 if( !pc->reg_load )
9280 p->flag.update = 1;/* either way, it will require either delete or replace */
9281 } else if( val[0] ) {
9282 struct DBData prev;
9283
9284 if( index )
9285 script->array_update(&sd->regs, reg, false);
9286
9287 p = ers_alloc(pc->str_reg_ers, struct script_reg_str);
9288
9289 p->value = aStrdup(val);
9290 if( !pc->reg_load )
9291 p->flag.update = 1;
9292 p->flag.type = 1;
9293
9294 if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) {
9295 p = DB->data2ptr(&prev);
9296 if( p->value )
9297 aFree(p->value);
9298 ers_free(pc->str_reg_ers, p);
9299 }
9300 }
9301
9302 if( !pc->reg_load && p )
9303 sd->vars_dirty = true;
9304
9305 return 1;
9306}
9307
9308/*==========================================
9309 * Exec eventtimer for player sd (retrieved from map_session (id))
9310 *------------------------------------------*/
9311int pc_eventtimer(int tid, int64 tick, int id, intptr_t data) {
9312 struct map_session_data *sd=map->id2sd(id);
9313 char *p = (char *)data;
9314 int i;
9315 if(sd==NULL)
9316 return 0;
9317
9318 ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] == tid );
9319 if( i < MAX_EVENTTIMER )
9320 {
9321 sd->eventtimer[i] = INVALID_TIMER;
9322 sd->eventcount--;
9323 npc->event(sd,p,0);
9324 }
9325 else
9326 ShowError("pc_eventtimer: no such event timer\n");
9327
9328 if (p) aFree(p);
9329 return 0;
9330}
9331
9332/*==========================================
9333 * Add eventtimer for player sd ?
9334 *------------------------------------------*/
9335int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name)
9336{
9337 int i;
9338 nullpo_ret(sd);
9339 nullpo_ret(name);
9340
9341 ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] == INVALID_TIMER );
9342 if( i == MAX_EVENTTIMER )
9343 return 0;
9344
9345 sd->eventtimer[i] = timer->add(timer->gettick()+tick, pc->eventtimer, sd->bl.id, (intptr_t)aStrdup(name));
9346 sd->eventcount++;
9347
9348 return 1;
9349}
9350
9351/*==========================================
9352 * Del eventtimer for player sd ?
9353 *------------------------------------------*/
9354int pc_deleventtimer(struct map_session_data *sd,const char *name)
9355{
9356 char* p = NULL;
9357 int i;
9358
9359 nullpo_ret(sd);
9360 nullpo_ret(name);
9361
9362 if (sd->eventcount <= 0)
9363 return 0;
9364
9365 // find the named event timer
9366 ARR_FIND( 0, MAX_EVENTTIMER, i,
9367 sd->eventtimer[i] != INVALID_TIMER &&
9368 (p = (char *)(timer->get(sd->eventtimer[i])->data)) != NULL &&
9369 strcmp(p, name) == 0
9370 );
9371 if( i == MAX_EVENTTIMER )
9372 return 0; // not found
9373
9374 timer->delete(sd->eventtimer[i],pc->eventtimer);
9375 sd->eventtimer[i] = INVALID_TIMER;
9376 sd->eventcount--;
9377 aFree(p);
9378
9379 return 1;
9380}
9381
9382/*==========================================
9383 * Update eventtimer count for player sd
9384 *------------------------------------------*/
9385int pc_addeventtimercount(struct map_session_data *sd,const char *name,int tick)
9386{
9387 int i;
9388
9389 nullpo_ret(sd);
9390
9391 for(i=0;i<MAX_EVENTTIMER;i++)
9392 if( sd->eventtimer[i] != INVALID_TIMER && strcmp(
9393 (char *)(timer->get(sd->eventtimer[i])->data), name)==0 ){
9394 timer->addtick(sd->eventtimer[i],tick);
9395 break;
9396 }
9397
9398 return 0;
9399}
9400
9401/*==========================================
9402 * Remove all eventtimer for player sd
9403 *------------------------------------------*/
9404int pc_cleareventtimer(struct map_session_data *sd)
9405{
9406 int i;
9407
9408 nullpo_ret(sd);
9409
9410 if (sd->eventcount <= 0)
9411 return 0;
9412
9413 for(i=0;i<MAX_EVENTTIMER;i++)
9414 if( sd->eventtimer[i] != INVALID_TIMER ){
9415 char *p = (char *)(timer->get(sd->eventtimer[i])->data);
9416 timer->delete(sd->eventtimer[i],pc->eventtimer);
9417 sd->eventtimer[i] = INVALID_TIMER;
9418 sd->eventcount--;
9419 if (p) aFree(p);
9420 }
9421 return 0;
9422}
9423/* called when a item with combo is worn */
9424int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) {
9425 int i, j, k, z;
9426 int index, success = 0;
9427 struct pc_combos *combo;
9428
9429 nullpo_ret(sd);
9430 nullpo_ret(data);
9431 for( i = 0; i < data->combos_count; i++ ) {
9432
9433 /* ensure this isn't a duplicate combo */
9434 if( sd->combos != NULL ) {
9435 int x;
9436
9437 ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id );
9438
9439 /* found a match, skip this combo */
9440 if( x < sd->combo_count )
9441 continue;
9442 }
9443
9444 for( j = 0; j < data->combos[i]->count; j++ ) {
9445 int id = data->combos[i]->nameid[j];
9446 bool found = false;
9447
9448 for( k = 0; k < EQI_MAX; k++ ) {
9449 index = sd->equip_index[k];
9450 if( index < 0 ) continue;
9451 if( k == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index ) continue;
9452 if( k == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index ) continue;
9453 if( k == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index) ) continue;
9454
9455 if(!sd->inventory_data[index])
9456 continue;
9457
9458 if ( itemdb_type(id) != IT_CARD ) {
9459 if ( sd->inventory_data[index]->nameid != id )
9460 continue;
9461
9462 found = true;
9463 break;
9464 } else { //Cards
9465 if ( sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->status.inventory[index].card[0]) )
9466 continue;
9467
9468 for (z = 0; z < sd->inventory_data[index]->slot; z++) {
9469
9470 if (sd->status.inventory[index].card[z] != id)
9471 continue;
9472
9473 // We have found a match
9474 found = true;
9475 break;
9476 }
9477 }
9478
9479 }
9480
9481 if( !found )
9482 break;/* we haven't found all the ids for this combo, so we can return */
9483 }
9484
9485 /* means we broke out of the count loop w/o finding all ids, we can move to the next combo */
9486 if( j < data->combos[i]->count )
9487 continue;
9488
9489 /* we got here, means all items in the combo are matching */
9490
9491 RECREATE(sd->combos, struct pc_combos, ++sd->combo_count);
9492 combo = &sd->combos[sd->combo_count - 1];
9493 combo->bonus = data->combos[i]->script;
9494 combo->id = data->combos[i]->id;
9495
9496 success++;
9497 }
9498
9499 return success;
9500}
9501
9502/* called when a item with combo is removed */
9503int pc_removecombo(struct map_session_data *sd, struct item_data *data ) {
9504 int i, retval = 0;
9505
9506 nullpo_ret(sd);
9507 nullpo_ret(data);
9508 if( !sd->combos )
9509 return 0;/* nothing to do here, player has no combos */
9510
9511 for( i = 0; i < data->combos_count; i++ ) {
9512 /* check if this combo exists in this user */
9513 int x = 0, cursor = 0, j;
9514
9515 ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id );
9516 /* no match, skip this combo */
9517 if( x == sd->combo_count )
9518 continue;
9519
9520 sd->combos[x].bonus = NULL;
9521 sd->combos[x].id = 0;
9522
9523 retval++;
9524
9525 for( j = 0, cursor = 0; j < sd->combo_count; j++ ) {
9526 if( sd->combos[j].bonus == NULL )
9527 continue;
9528
9529 if( cursor != j ) {
9530 sd->combos[cursor].bonus = sd->combos[j].bonus;
9531 sd->combos[cursor].id = sd->combos[j].id;
9532 }
9533
9534 cursor++;
9535 }
9536
9537 /* it's empty, we can clear all the memory */
9538 if( (sd->combo_count = cursor) == 0 ) {
9539 aFree(sd->combos);
9540 sd->combos = NULL;
9541 break;
9542 }
9543 }
9544
9545 /* check if combo requirements still fit -- don't touch retval! */
9546 pc->checkcombo( sd, data );
9547
9548 return retval;
9549}
9550int pc_load_combo(struct map_session_data *sd) {
9551 int i, ret = 0;
9552 nullpo_ret(sd);
9553 for( i = 0; i < EQI_MAX; i++ ) {
9554 struct item_data *id = NULL;
9555 int idx = sd->equip_index[i];
9556 if( sd->equip_index[i] < 0 || !(id = sd->inventory_data[idx] ) )
9557 continue;
9558 if( id->combos_count )
9559 ret += pc->checkcombo(sd,id);
9560 if(!itemdb_isspecial(sd->status.inventory[idx].card[0])) {
9561 struct item_data *data;
9562 int j;
9563 for( j = 0; j < id->slot; j++ ) {
9564 if (!sd->status.inventory[idx].card[j])
9565 continue;
9566 if ( ( data = itemdb->exists(sd->status.inventory[idx].card[j]) ) != NULL ) {
9567 if( data->combos_count )
9568 ret += pc->checkcombo(sd,data);
9569 }
9570 }
9571 }
9572 }
9573 return ret;
9574}
9575
9576/**
9577* Equip item at given position.
9578* @param sd the affected player structure. Must be checked before.
9579* @param id item structure for equip. Must be checked before.
9580* @param n inventory item position. Must be checked before.
9581* @param pos slot position. Must be checked before.
9582**/
9583void pc_equipitem_pos(struct map_session_data *sd, struct item_data *id, int n, int pos)
9584{
9585 nullpo_retv(sd);
9586 if ((!map_no_view(sd->bl.m,EQP_SHADOW_WEAPON) && pos & EQP_SHADOW_WEAPON) ||
9587 (pos & EQP_HAND_R)) {
9588 if(id)
9589 sd->weapontype1 = id->look;
9590 else
9591 sd->weapontype1 = 0;
9592 pc->calcweapontype(sd);
9593 clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
9594 }
9595 if ((!map_no_view(sd->bl.m,EQP_SHADOW_SHIELD) && pos & EQP_SHADOW_SHIELD) ||
9596 (pos & EQP_HAND_L)) {
9597 if (id) {
9598 if(id->type == IT_WEAPON) {
9599 sd->status.shield = 0;
9600 sd->weapontype2 = id->look;
9601 } else if(id->type == IT_ARMOR) {
9602 sd->status.shield = id->look;
9603 sd->weapontype2 = 0;
9604 }
9605 } else
9606 sd->status.shield = sd->weapontype2 = 0;
9607 pc->calcweapontype(sd);
9608 clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
9609 }
9610 //Added check to prevent sending the same look on multiple slots ->
9611 //causes client to redraw item on top of itself. (suggested by Lupus)
9612 if (!map_no_view(sd->bl.m,EQP_HEAD_LOW) && pos & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1) {
9613 if (id && !(pos&(EQP_HEAD_TOP|EQP_HEAD_MID)))
9614 sd->status.head_bottom = id->look;
9615 else
9616 sd->status.head_bottom = 0;
9617 clif->changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
9618 }
9619 if (!map_no_view(sd->bl.m,EQP_HEAD_TOP) && pos & EQP_HEAD_TOP && pc->checkequip(sd,EQP_COSTUME_HEAD_TOP) == -1) {
9620 if (id)
9621 sd->status.head_top = id->look;
9622 else
9623 sd->status.head_top = 0;
9624 clif->changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
9625 }
9626 if (!map_no_view(sd->bl.m,EQP_HEAD_MID) && pos & EQP_HEAD_MID && pc->checkequip(sd,EQP_COSTUME_HEAD_MID) == -1) {
9627 if (id && !(pos&EQP_HEAD_TOP))
9628 sd->status.head_mid = id->look;
9629 else
9630 sd->status.head_mid = 0;
9631 clif->changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
9632 }
9633 if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_TOP) && pos & EQP_COSTUME_HEAD_TOP) {
9634 if (id){
9635 sd->status.head_top = id->look;
9636 } else
9637 sd->status.head_top = 0;
9638 clif->changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
9639 }
9640 if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_MID) && pos & EQP_COSTUME_HEAD_MID) {
9641 if(id && !(pos&EQP_HEAD_TOP)){
9642 sd->status.head_mid = id->look;
9643 } else
9644 sd->status.head_mid = 0;
9645 clif->changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
9646 }
9647 if (!map_no_view(sd->bl.m,EQP_COSTUME_HEAD_LOW) && pos & EQP_COSTUME_HEAD_LOW) {
9648 if (id && !(pos&(EQP_HEAD_TOP|EQP_HEAD_MID))){
9649 sd->status.head_bottom = id->look;
9650 } else
9651 sd->status.head_bottom = 0;
9652 clif->changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
9653 }
9654
9655 if (!map_no_view(sd->bl.m,EQP_SHOES) && pos & EQP_SHOES)
9656 clif->changelook(&sd->bl,LOOK_SHOES,0);
9657 if (!map_no_view(sd->bl.m,EQP_GARMENT) && pos&EQP_GARMENT && pc->checkequip(sd,EQP_COSTUME_GARMENT) == -1) {
9658 sd->status.robe = id ? id->look : 0;
9659 clif->changelook(&sd->bl, LOOK_ROBE, sd->status.robe);
9660 }
9661
9662 if (!map_no_view(sd->bl.m,EQP_COSTUME_GARMENT) && pos & EQP_COSTUME_GARMENT) {
9663 sd->status.robe = id ? id->look : 0;
9664 clif->changelook(&sd->bl,LOOK_ROBE,sd->status.robe);
9665 }
9666}
9667
9668/*==========================================
9669 * Equip item on player sd at req_pos from inventory index n
9670 * Return:
9671 * 0 = fail
9672 * 1 = success
9673 *------------------------------------------*/
9674int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
9675{
9676 int i,pos,flag=0,iflag;
9677 struct item_data *id;
9678
9679 nullpo_ret(sd);
9680
9681 if( n < 0 || n >= MAX_INVENTORY ) {
9682 clif->equipitemack(sd,0,0,EIA_FAIL);
9683 return 0;
9684 }
9685
9686 if( DIFF_TICK(sd->canequip_tick,timer->gettick()) > 0 )
9687 {
9688 clif->equipitemack(sd,n,0,EIA_FAIL);
9689 return 0;
9690 }
9691
9692 id = sd->inventory_data[n];
9693 pos = pc->equippoint(sd,n); //With a few exceptions, item should go in all specified slots.
9694
9695 if(battle_config.battle_log)
9696 ShowInfo("equip %d(%d) %x:%x\n", sd->status.inventory[n].nameid, n, (unsigned int)(id ? id->equip : 0), (unsigned int)req_pos);
9697 if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ) { // [Valaris]
9698 // FIXME: pc->isequip: equip level failure uses 2 instead of 0
9699 clif->equipitemack(sd,n,0,EIA_FAIL); // fail
9700 return 0;
9701 }
9702
9703 if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP])
9704 {
9705 clif->equipitemack(sd,n,0,EIA_FAIL); // fail
9706 return 0;
9707 }
9708
9709 /* won't fail from this point onwards */
9710 if( id->flag.bindonequip && !sd->status.inventory[n].bound ) {
9711 sd->status.inventory[n].bound = (unsigned char)IBT_CHARACTER;
9712 clif->notify_bounditem(sd,n);
9713 }
9714
9715 if(pos == EQP_ACC) { //Accesories should only go in one of the two,
9716 pos = req_pos&EQP_ACC;
9717 if (pos == EQP_ACC) //User specified both slots..
9718 pos = sd->equip_index[EQI_ACC_R] >= 0 ? EQP_ACC_L : EQP_ACC_R;
9719 } else if(pos == EQP_ARMS && id->equip == EQP_HAND_R) { //Dual wield capable weapon.
9720 pos = (req_pos&EQP_ARMS);
9721 if (pos == EQP_ARMS) //User specified both slots, pick one for them.
9722 pos = sd->equip_index[EQI_HAND_R] >= 0 ? EQP_HAND_L : EQP_HAND_R;
9723 } else if(pos == EQP_SHADOW_ACC) { //Accesories should only go in one of the two,
9724 pos = req_pos&EQP_SHADOW_ACC;
9725 if (pos == EQP_SHADOW_ACC) //User specified both slots..
9726 pos = sd->equip_index[EQI_SHADOW_ACC_R] >= 0 ? EQP_SHADOW_ACC_L : EQP_SHADOW_ACC_R;
9727 } else if( pos == EQP_SHADOW_ARMS && id->equip == EQP_SHADOW_WEAPON) { //Dual wield capable weapon.
9728 pos = (req_pos&EQP_SHADOW_ARMS);
9729 if (pos == EQP_SHADOW_ARMS) //User specified both slots, pick one for them.
9730 pos = sd->equip_index[EQI_SHADOW_WEAPON] >= 0 ? EQP_SHADOW_SHIELD : EQP_SHADOW_WEAPON;
9731 }
9732
9733 if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) {
9734 //Update skill-block range database when weapon range changes. [Skotlex]
9735 i = sd->equip_index[EQI_HAND_R];
9736 if (i < 0 || !sd->inventory_data[i]) //No data, or no weapon equipped
9737 flag = 1;
9738 else
9739 flag = id->range != sd->inventory_data[i]->range;
9740 }
9741
9742 for(i=0;i<EQI_MAX;i++) {
9743 if(pos & pc->equip_pos[i]) {
9744 if(sd->equip_index[i] >= 0) //Slot taken, remove item from there.
9745 pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
9746
9747 sd->equip_index[i] = n;
9748 }
9749 }
9750
9751 if(pos==EQP_AMMO){
9752 clif->arrowequip(sd,n);
9753 clif->arrow_fail(sd,3);
9754 }
9755 else
9756 clif->equipitemack(sd,n,pos,EIA_SUCCESS);
9757
9758 sd->status.inventory[n].equip=pos;
9759
9760 pc->equipitem_pos(sd, id, n, pos);
9761
9762 pc->checkallowskill(sd); //Check if status changes should be halted.
9763 iflag = sd->npc_item_flag;
9764
9765 /* check for combos (MUST be before status_calc_pc) */
9766 if( id->combos_count )
9767 pc->checkcombo(sd,id);
9768 if(itemdb_isspecial(sd->status.inventory[n].card[0]))
9769 ; //No cards
9770 else {
9771 for( i = 0; i < id->slot; i++ ) {
9772 struct item_data *data;
9773 if (!sd->status.inventory[n].card[i])
9774 continue;
9775 if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
9776 if( data->combos_count )
9777 pc->checkcombo(sd,data);
9778 }
9779 }
9780 }
9781
9782 status_calc_pc(sd,SCO_NONE);
9783 if (flag) //Update skill data
9784 clif->skillinfoblock(sd);
9785
9786 //OnEquip script [Skotlex]
9787 if (id->equip_script)
9788 script->run_item_equip_script(sd, id, npc->fake_nd->bl.id);
9789
9790 if(itemdb_isspecial(sd->status.inventory[n].card[0]))
9791 ; //No cards
9792 else {
9793 for( i = 0; i < id->slot; i++ ) {
9794 struct item_data *data;
9795 if (!sd->status.inventory[n].card[i])
9796 continue;
9797 if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
9798 if (data->equip_script)
9799 script->run_item_equip_script(sd, data, npc->fake_nd->bl.id);
9800 }
9801 }
9802 }
9803 sd->npc_item_flag = iflag;
9804
9805 return 1;
9806}
9807
9808/**
9809* Unrquip item ad given position.
9810* @param sd the affected player structure. Must be checked before.
9811* @param n inventory item position. Must be checked before.
9812* @param pos slot position. Must be checked before.
9813**/
9814void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos)
9815{
9816 nullpo_retv(sd);
9817 if (pos & EQP_HAND_R) {
9818 sd->weapontype1 = 0;
9819 sd->status.weapon = sd->weapontype2;
9820 pc->calcweapontype(sd);
9821 clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
9822 if (!battle_config.dancing_weaponswitch_fix)
9823 status_change_end(&sd->bl, SC_DANCING, INVALID_TIMER); // Unequipping => stop dancing.
9824 }
9825 if (pos & EQP_HAND_L) {
9826 sd->status.shield = sd->weapontype2 = 0;
9827 pc->calcweapontype(sd);
9828 clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
9829 }
9830 if (pos & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1) {
9831 sd->status.head_bottom = 0;
9832 clif->changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
9833 }
9834 if (pos & EQP_HEAD_TOP && pc->checkequip(sd,EQP_COSTUME_HEAD_TOP) == -1) {
9835 sd->status.head_top = 0;
9836 clif->changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
9837 }
9838 if (pos & EQP_HEAD_MID && pc->checkequip(sd,EQP_COSTUME_HEAD_MID) == -1) {
9839 sd->status.head_mid = 0;
9840 clif->changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
9841 }
9842
9843 if (pos & EQP_COSTUME_HEAD_TOP) {
9844 sd->status.head_top = ( pc->checkequip(sd,EQP_HEAD_TOP) >= 0 ) ? sd->inventory_data[pc->checkequip(sd,EQP_HEAD_TOP)]->look : 0;
9845 clif->changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top);
9846 }
9847
9848 if (pos & EQP_COSTUME_HEAD_MID) {
9849 sd->status.head_mid = ( pc->checkequip(sd,EQP_HEAD_MID) >= 0 ) ? sd->inventory_data[pc->checkequip(sd,EQP_HEAD_MID)]->look : 0;
9850 clif->changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid);
9851 }
9852
9853 if (pos & EQP_COSTUME_HEAD_LOW) {
9854 sd->status.head_bottom = ( pc->checkequip(sd,EQP_HEAD_LOW) >= 0 ) ? sd->inventory_data[pc->checkequip(sd,EQP_HEAD_LOW)]->look : 0;
9855 clif->changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom);
9856 }
9857
9858 if (pos & EQP_SHOES)
9859 clif->changelook(&sd->bl,LOOK_SHOES,0);
9860
9861 if (pos & EQP_GARMENT && pc->checkequip(sd,EQP_COSTUME_GARMENT) == -1) {
9862 sd->status.robe = 0;
9863 clif->changelook(&sd->bl, LOOK_ROBE, 0);
9864 }
9865
9866 if (pos & EQP_COSTUME_GARMENT) {
9867 sd->status.robe = ( pc->checkequip(sd,EQP_GARMENT) >= 0 ) ? sd->inventory_data[pc->checkequip(sd,EQP_GARMENT)]->look : 0;
9868 clif->changelook(&sd->bl,LOOK_ROBE,sd->status.robe);
9869 }
9870}
9871
9872/*==========================================
9873 * Called when attemting to unequip an item from player
9874 * type: @see enum pc_unequipitem_flag
9875 * Return:
9876 * 0 = fail
9877 * 1 = success
9878 *------------------------------------------*/
9879int pc_unequipitem(struct map_session_data *sd,int n,int flag)
9880{
9881 int i,iflag;
9882 bool status_cacl = false;
9883 int pos;
9884 nullpo_ret(sd);
9885
9886 if( n < 0 || n >= MAX_INVENTORY ) {
9887 clif->unequipitemack(sd,0,0,UIA_FAIL);
9888 return 0;
9889 }
9890
9891 // if player is berserk then cannot unequip
9892 if (!(flag&PCUNEQUIPITEM_FORCE) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) )
9893 {
9894 clif->unequipitemack(sd,n,0,UIA_FAIL);
9895 return 0;
9896 }
9897
9898 if( !(flag&PCUNEQUIPITEM_FORCE) && sd->sc.count && sd->sc.data[SC_KYOUGAKU] )
9899 {
9900 clif->unequipitemack(sd,n,0,UIA_FAIL);
9901 return 0;
9902 }
9903
9904 if(battle_config.battle_log)
9905 ShowInfo("unequip %d %x:%x\n", n, (unsigned int)(pc->equippoint(sd, n)), sd->status.inventory[n].equip);
9906
9907 if(!sd->status.inventory[n].equip){ //Nothing to unequip
9908 clif->unequipitemack(sd,n,0,UIA_FAIL);
9909 return 0;
9910 }
9911 for(i=0;i<EQI_MAX;i++) {
9912 if(sd->status.inventory[n].equip & pc->equip_pos[i])
9913 sd->equip_index[i] = -1;
9914 }
9915
9916 pos = sd->status.inventory[n].equip;
9917 pc->unequipitem_pos(sd, n, pos);
9918
9919 clif->unequipitemack(sd,n,pos,UIA_SUCCESS);
9920
9921 if((pos & EQP_ARMS) &&
9922 sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_TK_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!)
9923 skill->enchant_elemental_end(&sd->bl,-1);
9924
9925 if(pos & EQP_ARMOR) {
9926 // On Armor Change...
9927 status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER);
9928 status_change_end(&sd->bl, SC_ARMOR_RESIST, INVALID_TIMER);
9929 }
9930
9931 if( sd->state.autobonus&pos )
9932 sd->state.autobonus &= ~sd->status.inventory[n].equip; //Check for activated autobonus [Inkfish]
9933
9934 sd->status.inventory[n].equip=0;
9935 iflag = sd->npc_item_flag;
9936
9937 /* check for combos (MUST be before status_calc_pc) */
9938 if ( sd->inventory_data[n] ) {
9939 if( sd->inventory_data[n]->combos_count ) {
9940 if( pc->removecombo(sd,sd->inventory_data[n]) )
9941 status_cacl = true;
9942 } if(itemdb_isspecial(sd->status.inventory[n].card[0]))
9943 ; //No cards
9944 else {
9945 for( i = 0; i < sd->inventory_data[n]->slot; i++ ) {
9946 struct item_data *data;
9947 if (!sd->status.inventory[n].card[i])
9948 continue;
9949 if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
9950 if( data->combos_count ) {
9951 if( pc->removecombo(sd,data) )
9952 status_cacl = true;
9953 }
9954 }
9955 }
9956 }
9957 }
9958
9959 if(flag&PCUNEQUIPITEM_RECALC || status_cacl) {
9960 pc->checkallowskill(sd);
9961 status_calc_pc(sd,SCO_NONE);
9962 }
9963
9964 if(sd->sc.data[SC_CRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele))
9965 status_change_end(&sd->bl, SC_CRUCIS, INVALID_TIMER);
9966
9967 //OnUnEquip script [Skotlex]
9968 if (sd->inventory_data[n]) {
9969 if (sd->inventory_data[n]->unequip_script) {
9970 if ( battle_config.unequip_restricted_equipment & 1 ) {
9971 ARR_FIND(0, map->list[sd->bl.m].zone->disabled_items_count, i, map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].nameid);
9972 if ( i == map->list[sd->bl.m].zone->disabled_items_count )
9973 script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
9974 }
9975 else
9976 script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
9977 }
9978 if(itemdb_isspecial(sd->status.inventory[n].card[0]))
9979 ; //No cards
9980 else {
9981 for( i = 0; i < sd->inventory_data[n]->slot; i++ ) {
9982 struct item_data *data;
9983 if (!sd->status.inventory[n].card[i])
9984 continue;
9985
9986 if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
9987 if ( data->unequip_script ) {
9988 if ( battle_config.unequip_restricted_equipment & 2 ) {
9989 int j;
9990 ARR_FIND(0, map->list[sd->bl.m].zone->disabled_items_count, j, map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[n].card[i]);
9991 if ( j == map->list[sd->bl.m].zone->disabled_items_count )
9992 script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id);
9993 }
9994 else
9995 script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id);
9996 }
9997 }
9998
9999 }
10000 }
10001 }
10002 sd->npc_item_flag = iflag;
10003
10004 return 1;
10005}
10006
10007/*==========================================
10008 * Checking if player (sd) have unauthorize, invalide item
10009 * on inventory, cart, equiped for the map (item_noequip)
10010 *------------------------------------------*/
10011int pc_checkitem(struct map_session_data *sd)
10012{
10013 int i, calc_flag = 0;
10014
10015 nullpo_ret(sd);
10016
10017 if (sd->state.vending) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam)
10018 return 0;
10019
10020 if (sd->state.itemcheck) { // check for invalid(ated) items
10021 int id;
10022 for (i = 0; i < MAX_INVENTORY; i++) {
10023 id = sd->status.inventory[i].nameid;
10024
10025 if (!id)
10026 continue;
10027
10028 if (!itemdb_available(id)) {
10029 ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id);
10030 pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_INV_INVALID);
10031 continue;
10032 }
10033
10034 if (!sd->status.inventory[i].unique_id && !itemdb->isstackable(id))
10035 sd->status.inventory[i].unique_id = itemdb->unique_id(sd);
10036 }
10037
10038 for( i = 0; i < MAX_CART; i++ ) {
10039 id = sd->status.cart[i].nameid;
10040
10041 if (!id)
10042 continue;
10043
10044 if( !itemdb_available(id) ) {
10045 ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id);
10046 pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_CART_INVALID);
10047 continue;
10048 }
10049
10050 if ( !sd->status.cart[i].unique_id && !itemdb->isstackable(id) )
10051 sd->status.cart[i].unique_id = itemdb->unique_id(sd);
10052 }
10053
10054 for( i = 0; i < MAX_STORAGE; i++ ) {
10055 id = sd->status.storage.items[i].nameid;
10056
10057 if (!id)
10058 continue;
10059
10060 if( id && !itemdb_available(id) ) {
10061 ShowWarning("Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, sd->status.storage.items[i].amount, sd->status.char_id);
10062 storage->delitem(sd, i, sd->status.storage.items[i].amount);
10063 storage->close(sd);
10064 continue;
10065 }
10066
10067 if ( !sd->status.storage.items[i].unique_id && !itemdb->isstackable(id) )
10068 sd->status.storage.items[i].unique_id = itemdb->unique_id(sd);
10069 }
10070
10071 if (sd->guild) {
10072 struct guild_storage *guild_storage = idb_get(gstorage->db,sd->guild->guild_id);
10073 if (guild_storage) {
10074 for( i = 0; i < MAX_GUILD_STORAGE; i++ ) {
10075 id = guild_storage->items[i].nameid;
10076
10077 if (!id)
10078 continue;
10079
10080 if( !itemdb_available(id) ) {
10081 ShowWarning("Removed invalid/disabled item id %d from guild storage (amount=%d, char_id=%d, guild_id=%d).\n", id, guild_storage->items[i].amount, sd->status.char_id, sd->guild->guild_id);
10082 gstorage->delitem(sd, guild_storage, i, guild_storage->items[i].amount);
10083 gstorage->close(sd); // force closing
10084 continue;
10085 }
10086
10087 if (!guild_storage->items[i].unique_id && !itemdb->isstackable(id))
10088 guild_storage->items[i].unique_id = itemdb->unique_id(sd);
10089 }
10090 }
10091 }
10092 sd->state.itemcheck = 0;
10093 }
10094
10095 for( i = 0; i < MAX_INVENTORY; i++) {
10096
10097 if( sd->status.inventory[i].nameid == 0 )
10098 continue;
10099
10100 if( !sd->status.inventory[i].equip )
10101 continue;
10102
10103 if( sd->status.inventory[i].equip&~pc->equippoint(sd,i) ) {
10104 pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
10105 calc_flag = 1;
10106 continue;
10107 }
10108
10109 if (battle_config.unequip_restricted_equipment&1) {
10110 int j;
10111 for (j = 0; j < map->list[sd->bl.m].zone->disabled_items_count; j++) {
10112 if (map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[i].nameid) {
10113 pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
10114 calc_flag = 1;
10115 }
10116 }
10117 }
10118
10119 if (battle_config.unequip_restricted_equipment&2) {
10120 if (!itemdb_isspecial(sd->status.inventory[i].card[0])) {
10121 int j, slot;
10122 for (slot = 0; slot < MAX_SLOTS; slot++) {
10123 for (j = 0; j < map->list[sd->bl.m].zone->disabled_items_count; j++) {
10124 if (map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[i].card[slot]) {
10125 pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
10126 calc_flag = 1;
10127 }
10128 }
10129 }
10130 }
10131 }
10132
10133 }
10134
10135 if( calc_flag && sd->state.active ) {
10136 pc->checkallowskill(sd);
10137 status_calc_pc(sd,SCO_NONE);
10138 }
10139
10140 return 0;
10141}
10142
10143/*==========================================
10144 * Update PVP rank for sd1 in cmp to sd2
10145 *------------------------------------------*/
10146int pc_calc_pvprank_sub(struct block_list *bl, va_list ap)
10147{
10148 struct map_session_data *sd1 = NULL;
10149 struct map_session_data *sd2 = va_arg(ap,struct map_session_data *);
10150
10151 nullpo_ret(bl);
10152 Assert_ret(bl->type == BL_PC);
10153 sd1 = BL_UCAST(BL_PC, bl);
10154 nullpo_ret(sd2);
10155
10156 if (pc_isinvisible(sd1) ||pc_isinvisible(sd2)) {
10157 // cannot register pvp rank for hidden GMs
10158 return 0;
10159 }
10160
10161 if( sd1->pvp_point > sd2->pvp_point )
10162 sd2->pvp_rank++;
10163 return 0;
10164}
10165/*==========================================
10166 * Calculate new rank beetween all present players (map->foreachinarea)
10167 * and display result
10168 *------------------------------------------*/
10169int pc_calc_pvprank(struct map_session_data *sd) {
10170 int old;
10171 struct map_data *m;
10172 nullpo_ret(sd);
10173 m=&map->list[sd->bl.m];
10174 old=sd->pvp_rank;
10175 sd->pvp_rank=1;
10176 map->foreachinmap(pc_calc_pvprank_sub,sd->bl.m,BL_PC,sd);
10177 if(old!=sd->pvp_rank || sd->pvp_lastusers!=m->users_pvp)
10178 clif->pvpset(sd,sd->pvp_rank,sd->pvp_lastusers=m->users_pvp,0);
10179 return sd->pvp_rank;
10180}
10181/*==========================================
10182 * Calculate next sd ranking calculation from config
10183 *------------------------------------------*/
10184int pc_calc_pvprank_timer(int tid, int64 tick, int id, intptr_t data) {
10185 struct map_session_data *sd;
10186
10187 sd=map->id2sd(id);
10188 if(sd==NULL)
10189 return 0;
10190 sd->pvp_timer = INVALID_TIMER;
10191
10192 if (pc_isinvisible(sd)) {
10193 // do not calculate the pvp rank for a hidden GM
10194 return 0;
10195 }
10196
10197 if( pc->calc_pvprank(sd) > 0 )
10198 sd->pvp_timer = timer->add(timer->gettick()+PVP_CALCRANK_INTERVAL,pc->calc_pvprank_timer,id,data);
10199 return 0;
10200}
10201
10202/*==========================================
10203 * Checking if sd is married
10204 * Return:
10205 * partner_id = yes
10206 * 0 = no
10207 *------------------------------------------*/
10208int pc_ismarried(struct map_session_data *sd)
10209{
10210 if(sd == NULL)
10211 return -1;
10212 if(sd->status.partner_id > 0)
10213 return sd->status.partner_id;
10214 else
10215 return 0;
10216}
10217/*==========================================
10218 * Marry player sd to player dstsd
10219 * Return:
10220 * -1 = fail
10221 * 0 = success
10222 *------------------------------------------*/
10223int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd)
10224{
10225 if(sd == NULL || dstsd == NULL ||
10226 sd->status.partner_id > 0 || dstsd->status.partner_id > 0 ||
10227 (sd->class_&JOBL_BABY) || (dstsd->class_&JOBL_BABY))
10228 return -1;
10229 sd->status.partner_id = dstsd->status.char_id;
10230 dstsd->status.partner_id = sd->status.char_id;
10231 return 0;
10232}
10233
10234/*==========================================
10235 * Divorce sd from its partner
10236 * Return:
10237 * -1 = fail
10238 * 0 = success
10239 *------------------------------------------*/
10240int pc_divorce(struct map_session_data *sd)
10241{
10242 struct map_session_data *p_sd;
10243 int i;
10244
10245 if( sd == NULL || !pc->ismarried(sd) )
10246 return -1;
10247
10248 if( !sd->status.partner_id )
10249 return -1; // Char is not married
10250
10251 if( (p_sd = map->charid2sd(sd->status.partner_id)) == NULL ) {
10252 // Lets char server do the divorce
10253 if( chrif->divorce(sd->status.char_id, sd->status.partner_id) )
10254 return -1; // No char server connected
10255
10256 return 0;
10257 }
10258
10259 // Both players online, lets do the divorce manually
10260 sd->status.partner_id = 0;
10261 p_sd->status.partner_id = 0;
10262 for( i = 0; i < MAX_INVENTORY; i++ )
10263 {
10264 if( sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F )
10265 pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE);
10266 if( p_sd->status.inventory[i].nameid == WEDDING_RING_M || p_sd->status.inventory[i].nameid == WEDDING_RING_F )
10267 pc->delitem(p_sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE);
10268 }
10269
10270 clif->divorced(sd, p_sd->status.name);
10271 clif->divorced(p_sd, sd->status.name);
10272
10273 return 0;
10274}
10275
10276/*==========================================
10277 * Get sd partner charid. (Married partner)
10278 *------------------------------------------*/
10279struct map_session_data *pc_get_partner(struct map_session_data *sd) {
10280 if (sd && pc->ismarried(sd))
10281 // charid2sd returns NULL if not found
10282 return map->charid2sd(sd->status.partner_id);
10283
10284 return NULL;
10285}
10286
10287/*==========================================
10288 * Get sd father charid. (Need to be baby)
10289 *------------------------------------------*/
10290struct map_session_data *pc_get_father(struct map_session_data *sd) {
10291 if (sd && sd->class_&JOBL_BABY && sd->status.father > 0)
10292 // charid2sd returns NULL if not found
10293 return map->charid2sd(sd->status.father);
10294
10295 return NULL;
10296}
10297
10298/*==========================================
10299 * Get sd mother charid. (Need to be baby)
10300 *------------------------------------------*/
10301struct map_session_data *pc_get_mother(struct map_session_data *sd) {
10302 if (sd && sd->class_&JOBL_BABY && sd->status.mother > 0)
10303 // charid2sd returns NULL if not found
10304 return map->charid2sd(sd->status.mother);
10305
10306 return NULL;
10307}
10308
10309/*==========================================
10310 * Get sd children charid. (Need to be married)
10311 *------------------------------------------*/
10312struct map_session_data *pc_get_child(struct map_session_data *sd) {
10313 if (sd && pc->ismarried(sd) && sd->status.child > 0)
10314 // charid2sd returns NULL if not found
10315 return map->charid2sd(sd->status.child);
10316
10317 return NULL;
10318}
10319
10320/*==========================================
10321 * Set player sd to bleed. (losing hp and/or sp each diff_tick)
10322 *------------------------------------------*/
10323void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick)
10324{
10325 int hp = 0, sp = 0;
10326
10327 nullpo_retv(sd);
10328 if( pc_isdead(sd) )
10329 return;
10330
10331 if (sd->hp_loss.value) {
10332 sd->hp_loss.tick += diff_tick;
10333 while (sd->hp_loss.tick >= sd->hp_loss.rate) {
10334 hp += sd->hp_loss.value;
10335 sd->hp_loss.tick -= sd->hp_loss.rate;
10336 }
10337 if(hp >= sd->battle_status.hp)
10338 hp = sd->battle_status.hp-1; //Script drains cannot kill you.
10339 }
10340
10341 if (sd->sp_loss.value) {
10342 sd->sp_loss.tick += diff_tick;
10343 while (sd->sp_loss.tick >= sd->sp_loss.rate) {
10344 sp += sd->sp_loss.value;
10345 sd->sp_loss.tick -= sd->sp_loss.rate;
10346 }
10347 }
10348
10349 if (hp > 0 || sp > 0)
10350 status_zap(&sd->bl, hp, sp);
10351
10352 return;
10353}
10354
10355//Character regen. Flag is used to know which types of regen can take place.
10356//&1: HP regen
10357//&2: SP regen
10358void pc_regen (struct map_session_data *sd, unsigned int diff_tick) {
10359 int hp = 0, sp = 0;
10360
10361 nullpo_retv(sd);
10362 if (sd->hp_regen.value) {
10363 sd->hp_regen.tick += diff_tick;
10364 while (sd->hp_regen.tick >= sd->hp_regen.rate) {
10365 hp += sd->hp_regen.value;
10366 sd->hp_regen.tick -= sd->hp_regen.rate;
10367 }
10368 }
10369
10370 if (sd->sp_regen.value) {
10371 sd->sp_regen.tick += diff_tick;
10372 while (sd->sp_regen.tick >= sd->sp_regen.rate) {
10373 sp += sd->sp_regen.value;
10374 sd->sp_regen.tick -= sd->sp_regen.rate;
10375 }
10376 }
10377
10378 if (hp > 0 || sp > 0)
10379 status->heal(&sd->bl, hp, sp, 0);
10380
10381 return;
10382}
10383
10384/*==========================================
10385 * Memo player sd savepoint. (map,x,y)
10386 *------------------------------------------*/
10387int pc_setsavepoint(struct map_session_data *sd, short map_index, int x, int y) {
10388 nullpo_ret(sd);
10389
10390 sd->status.save_point.map = map_index;
10391 sd->status.save_point.x = x;
10392 sd->status.save_point.y = y;
10393
10394 return 0;
10395}
10396
10397/*==========================================
10398 * Save 1 player data at autosave intervall
10399 *------------------------------------------*/
10400int pc_autosave(int tid, int64 tick, int id, intptr_t data) {
10401 int interval;
10402 struct s_mapiterator* iter;
10403 struct map_session_data* sd;
10404 static int last_save_id = 0, save_flag = 0;
10405
10406 if(save_flag == 2) //Someone was saved on last call, normal cycle
10407 save_flag = 0;
10408 else
10409 save_flag = 1; //Noone was saved, so save first found char.
10410
10411 iter = mapit_getallusers();
10412 for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
10413 if(sd->bl.id == last_save_id && save_flag != 1) {
10414 save_flag = 1;
10415 continue;
10416 }
10417
10418 if(save_flag != 1) //Not our turn to save yet.
10419 continue;
10420
10421 //Save char.
10422 last_save_id = sd->bl.id;
10423 save_flag = 2;
10424
10425 chrif->save(sd,0);
10426 break;
10427 }
10428 mapit->free(iter);
10429
10430 interval = map->autosave_interval/(map->usercount()+1);
10431 if(interval < map->minsave_interval)
10432 interval = map->minsave_interval;
10433 timer->add(timer->gettick()+interval,pc->autosave,0,0);
10434
10435 return 0;
10436}
10437
10438int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) {
10439 nullpo_ret(sd);
10440 if (sd->state.night != map->night_flag && map->list[sd->bl.m].flag.nightenabled) { //Night/day state does not match.
10441 clif->status_change(&sd->bl, SI_SKE, map->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex]
10442 sd->state.night = map->night_flag;
10443 return 1;
10444 }
10445 return 0;
10446}
10447/*================================================
10448 * timer to do the day [Yor]
10449 * data: 0 = called by timer, 1 = gmcommand/script
10450 *------------------------------------------------*/
10451int map_day_timer(int tid, int64 tick, int id, intptr_t data) {
10452 char tmp_soutput[1024];
10453
10454 if (data == 0 && battle_config.day_duration <= 0) // if we want a day
10455 return 0;
10456
10457 if (!map->night_flag)
10458 return 0; //Already day.
10459
10460 map->night_flag = 0; // 0=day, 1=night [Yor]
10461 map->foreachpc(pc->daynight_timer_sub);
10462 safestrncpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60), sizeof(tmp_soutput)); // The day has arrived!
10463 intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT);
10464 return 0;
10465}
10466
10467/*================================================
10468 * timer to do the night [Yor]
10469 * data: 0 = called by timer, 1 = gmcommand/script
10470 *------------------------------------------------*/
10471int map_night_timer(int tid, int64 tick, int id, intptr_t data) {
10472 char tmp_soutput[1024];
10473
10474 if (data == 0 && battle_config.night_duration <= 0) // if we want a night
10475 return 0;
10476
10477 if (map->night_flag)
10478 return 0; //Already nigth.
10479
10480 map->night_flag = 1; // 0=day, 1=night [Yor]
10481 map->foreachpc(pc->daynight_timer_sub);
10482 safestrncpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59), sizeof(tmp_soutput)); // The night has fallen...
10483 intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT);
10484 return 0;
10485}
10486
10487void pc_setstand(struct map_session_data *sd) {
10488 nullpo_retv(sd);
10489
10490 status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER);
10491 clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
10492 //Reset sitting tick.
10493 sd->ssregen.tick.hp = sd->ssregen.tick.sp = 0;
10494 sd->state.dead_sit = sd->vd.dead_sit = 0;
10495}
10496
10497/**
10498 * Mechanic (MADO GEAR)
10499 **/
10500void pc_overheat(struct map_session_data *sd, int val) {
10501 int heat = val, skill_lv,
10502 limit[] = { 10, 20, 28, 46, 66 };
10503
10504 nullpo_retv(sd);
10505 if( !pc_ismadogear(sd) || sd->sc.data[SC_OVERHEAT] )
10506 return; // already burning
10507
10508 skill_lv = cap_value(pc->checkskill(sd,NC_MAINFRAME),0,4);
10509 if( sd->sc.data[SC_OVERHEAT_LIMITPOINT] ) {
10510 heat += sd->sc.data[SC_OVERHEAT_LIMITPOINT]->val1;
10511 status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER);
10512 }
10513
10514 heat = max(0,heat); // Avoid negative HEAT
10515 if( heat >= limit[skill_lv] )
10516 sc_start(NULL,&sd->bl,SC_OVERHEAT,100,0,1000);
10517 else
10518 sc_start(NULL,&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000);
10519
10520 return;
10521}
10522
10523/**
10524 * Check if player is autolooting given itemID.
10525 */
10526bool pc_isautolooting(struct map_session_data *sd, int nameid)
10527{
10528 int i = 0;
10529
10530 nullpo_ret(sd);
10531 if (sd->state.autoloottype && sd->state.autoloottype&(1<<itemdb_type(nameid)))
10532 return true;
10533
10534 if (!sd->state.autolooting)
10535 return false;
10536
10537 ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == nameid);
10538
10539 return (i != AUTOLOOTITEM_SIZE);
10540}
10541
10542/**
10543 * Checks if player can use @/#command
10544 * @param sd Player map session data
10545 * @param command Command name with @/# and without params
10546 */
10547bool pc_can_use_command(struct map_session_data *sd, const char *command) {
10548 return atcommand->can_use(sd,command);
10549}
10550
10551/**
10552 * Spirit Charm expiration timer.
10553 *
10554 * @see TimerFunc
10555 */
10556int pc_charm_timer(int tid, int64 tick, int id, intptr_t data)
10557{
10558 struct map_session_data *sd = map->id2sd(id);
10559 int i;
10560
10561 if (sd == NULL)
10562 return 1;
10563
10564 if (sd->charm_count <= 0) {
10565 ShowError("pc_charm_timer: %d spiritcharm's available. (aid=%d cid=%d tid=%d)\n", sd->charm_count, sd->status.account_id, sd->status.char_id, tid);
10566 sd->charm_count = 0;
10567 sd->charm_type = CHARM_TYPE_NONE;
10568 return 0;
10569 }
10570
10571 ARR_FIND(0, sd->charm_count, i, sd->charm_timer[i] == tid);
10572 if (i == sd->charm_count) {
10573 ShowError("pc_charm_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid);
10574 return 0;
10575 }
10576
10577 sd->charm_count--;
10578 if(i != sd->charm_count)
10579 memmove(sd->charm_timer+i, sd->charm_timer+i+1, (sd->charm_count-i)*sizeof(int));
10580 sd->charm_timer[sd->charm_count] = INVALID_TIMER;
10581 if (sd->charm_count <= 0)
10582 sd->charm_type = CHARM_TYPE_NONE;
10583
10584 clif->spiritcharm(sd);
10585
10586 return 0;
10587}
10588
10589/**
10590 * Adds a spirit charm.
10591 *
10592 * @param sd Target character.
10593 * @param interval Duration.
10594 * @param max Maximum amount of charms to add.
10595 * @param type Charm type (@see spirit_charm_types)
10596 */
10597void pc_add_charm(struct map_session_data *sd, int interval, int max, int type)
10598{
10599 int tid, i;
10600
10601 nullpo_retv(sd);
10602
10603 if (sd->charm_type != CHARM_TYPE_NONE && type != sd->charm_type) {
10604 pc->del_charm(sd, sd->charm_count, sd->charm_type);
10605 }
10606
10607 if (max > MAX_SPIRITCHARM)
10608 max = MAX_SPIRITCHARM;
10609 if (sd->charm_count < 0)
10610 sd->charm_count = 0;
10611
10612 if (sd->charm_count && sd->charm_count >= max) {
10613 if (sd->charm_timer[0] != INVALID_TIMER)
10614 timer->delete(sd->charm_timer[0],pc->charm_timer);
10615 sd->charm_count--;
10616 if (sd->charm_count != 0)
10617 memmove(sd->charm_timer+0, sd->charm_timer+1, sd->charm_count*sizeof(int));
10618 sd->charm_timer[sd->charm_count] = INVALID_TIMER;
10619 }
10620
10621 tid = timer->add(timer->gettick()+interval, pc->charm_timer, sd->bl.id, 0);
10622 ARR_FIND(0, sd->charm_count, i, sd->charm_timer[i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->charm_timer[i])->tick) < 0);
10623 if (i != sd->charm_count)
10624 memmove(sd->charm_timer+i+1, sd->charm_timer+i, (sd->charm_count-i)*sizeof(int));
10625 sd->charm_timer[i] = tid;
10626 sd->charm_count++;
10627 sd->charm_type = type;
10628
10629 clif->spiritcharm(sd);
10630}
10631
10632/**
10633 * Removes one or more spirit charms.
10634 *
10635 * @param sd The target character.
10636 * @param count Amount of charms to remove.
10637 * @param type Type of charm to remove.
10638 */
10639void pc_del_charm(struct map_session_data *sd, int count, int type)
10640{
10641 int i;
10642
10643 nullpo_retv(sd);
10644
10645 if (sd->charm_type != type)
10646 return;
10647
10648 if (sd->charm_count <= 0) {
10649 sd->charm_count = 0;
10650 return;
10651 }
10652
10653 if (count <= 0)
10654 return;
10655 if (count > sd->charm_count)
10656 count = sd->charm_count;
10657 sd->charm_count -= count;
10658 if (count > MAX_SPIRITCHARM)
10659 count = MAX_SPIRITCHARM;
10660
10661 for (i = 0; i < count; i++) {
10662 if(sd->charm_timer[i] != INVALID_TIMER) {
10663 timer->delete(sd->charm_timer[i],pc->charm_timer);
10664 sd->charm_timer[i] = INVALID_TIMER;
10665 }
10666 }
10667 for (i = count; i < MAX_SPIRITCHARM; i++) {
10668 sd->charm_timer[i-count] = sd->charm_timer[i];
10669 sd->charm_timer[i] = INVALID_TIMER;
10670 }
10671 if (sd->charm_count <= 0)
10672 sd->charm_type = CHARM_TYPE_NONE;
10673
10674 clif->spiritcharm(sd);
10675}
10676
10677/**
10678 * Renewal EXP/Itemdrop rate modifier base on level penalty.
10679 *
10680 * @param diff Level difference.
10681 * @param race Monster race.
10682 * @param mode Monster mode.
10683 * @param type Modifier type (1=exp 2=itemdrop)
10684 * @return The percent rate modifier (100 = 100%)
10685 */
10686int pc_level_penalty_mod(int diff, unsigned char race, uint32 mode, int type)
10687{
10688#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
10689 int rate = 100, i;
10690
10691 if( diff < 0 )
10692 diff = MAX_LEVEL + ( ~diff + 1 );
10693
10694 for (i = RC_FORMLESS; i < RC_MAX; i++) {
10695 int tmp;
10696
10697 if (race != i) {
10698 if (mode&MD_BOSS && i < RC_BOSS)
10699 i = RC_BOSS;
10700 else if (i <= RC_BOSS)
10701 continue;
10702 }
10703
10704 if ((tmp=pc->level_penalty[type][i][diff]) > 0) {
10705 rate = tmp;
10706 break;
10707 }
10708 }
10709
10710 return rate;
10711#else
10712 return 100;
10713#endif
10714}
10715int pc_split_str(char *str,char **val,int num)
10716{
10717 int i;
10718
10719 nullpo_ret(val);
10720 for (i=0; i<num && str; i++){
10721 val[i] = str;
10722 str = strchr(str,',');
10723 if (str && i<num-1) //Do not remove a trailing comma.
10724 *str++=0;
10725 }
10726 return i;
10727}
10728
10729int pc_split_atoi(char* str, int* val, char sep, int max)
10730{
10731 int i,j;
10732 nullpo_ret(val);
10733 for (i=0; i<max; i++) {
10734 if (!str) break;
10735 val[i] = atoi(str);
10736 str = strchr(str,sep);
10737 if (str)
10738 *str++=0;
10739 }
10740 //Zero up the remaining.
10741 for(j=i; j < max; j++)
10742 val[j] = 0;
10743 return i;
10744}
10745
10746int pc_split_atoui(char* str, unsigned int* val, char sep, int max)
10747{
10748 static int warning=0;
10749 int i,j;
10750 nullpo_ret(val);
10751 for (i=0; i<max; i++) {
10752 double f;
10753 if (!str) break;
10754 f = atof(str);
10755 if (f < 0)
10756 val[i] = 0;
10757 else if (f > UINT_MAX) {
10758 val[i] = UINT_MAX;
10759 if (!warning) {
10760 warning = 1;
10761 ShowWarning("pc_readdb (exp.txt): Required exp per level is capped to %u\n", UINT_MAX);
10762 }
10763 } else
10764 val[i] = (unsigned int)f;
10765 str = strchr(str,sep);
10766 if (str)
10767 *str++=0;
10768 }
10769 //Zero up the remaining.
10770 for(j=i; j < max; j++)
10771 val[j] = 0;
10772 return i;
10773}
10774
10775/**
10776 * Parses the skill tree config file.
10777 *
10778 * In order to reclaim the memory allocated by this function
10779 * `pc->clear_skill_tree()` should be used.
10780 *
10781 * @remark
10782 * This function assumes that the skill tree is clear and zeroed.
10783 * If it has been already loaded (ie reloading), it needs to be cleared
10784 * before calling this function again.
10785 *
10786 * @author [Ind/Hercules]
10787 */
10788void pc_read_skill_tree(void)
10789{
10790 struct config_t skill_tree_conf;
10791 struct config_setting_t *skt = NULL;
10792 char config_filename[128];
10793 int i = 0;
10794 struct s_mapiterator *iter;
10795 struct map_session_data *sd;
10796 bool loaded[CLASS_COUNT] = { false };
10797
10798 safesnprintf(config_filename, sizeof(config_filename), "%s/"DBPATH"skill_tree.conf", map->db_path);
10799 if (!libconfig->load_file(&skill_tree_conf, config_filename))
10800 return;
10801
10802 // Foreach job
10803 while ((skt = libconfig->setting_get_elem(skill_tree_conf.root, i++))) {
10804 struct config_setting_t *t = NULL;
10805 int job_idx;
10806 const char *job_name = config_setting_name(skt);
10807 int job_id = pc->check_job_name(job_name);
10808
10809 if (job_id == -1) {
10810 ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n", job_name);
10811 continue;
10812 }
10813 job_idx = pc->class2idx(job_id);
10814 if (loaded[job_idx]) {
10815 ShowWarning("pc_read_skill_tree: Duplicate entry for job '%s'. Skipping.\n", job_name);
10816 continue;
10817 }
10818 loaded[job_idx] = true;
10819
10820 if ((t = libconfig->setting_get_member(skt, "inherit")) != NULL) {
10821 int j = 0;
10822 const char *ijob_name = NULL;
10823 // Foreach inherited job
10824 while ((ijob_name = libconfig->setting_get_string_elem(t, j++)) != NULL) {
10825 int k, ijob_idx;
10826 int ijob_id = pc->check_job_name(ijob_name);
10827
10828 if (ijob_id == -1) {
10829 ShowWarning("pc_read_skill_tree: '%s' trying to inherit unknown '%s'!\n", job_name, ijob_name);
10830 continue;
10831 }
10832 ijob_idx = pc->class2idx(ijob_id);
10833 if (ijob_idx == job_idx) {
10834 ShowWarning("pc_read_skill_tree: '%s' trying to inherit itself. Skipping.\n", job_name);
10835 continue;
10836 }
10837 if (!loaded[ijob_idx]) {
10838 ShowWarning("pc_read_skill_tree: '%s' trying to inherit not yet loaded '%s' (wrong order in the tree). Skipping.\n", job_name, ijob_name);
10839 continue;
10840 }
10841
10842 for (k = 0; k < MAX_SKILL_TREE; k++) {
10843 int cur;
10844 struct skill_tree_entry *dst = NULL;
10845 const struct skill_tree_entry *src = &pc->skill_tree[ijob_idx][k];
10846
10847 if (src->id == 0)
10848 break; // No more skills to copy
10849
10850 ARR_FIND(0, MAX_SKILL_TREE, cur, pc->skill_tree[job_idx][cur].id == 0 || pc->skill_tree[job_idx][cur].id == src->id);
10851 if (cur == MAX_SKILL_TREE) {
10852 ShowWarning("pc_read_skill_tree: '%s' can't inherit '%s', skill tree is full!\n", job_name, ijob_name);
10853 break;
10854 }
10855 if (src->id == NV_TRICKDEAD && ((pc->jobid2mapid(job_id)&(MAPID_BASEMASK | JOBL_2)) != MAPID_NOVICE))
10856 continue; // skip trickdead for non-novices
10857 dst = &pc->skill_tree[job_idx][cur];
10858 dst->inherited = 1;
10859 if (dst->id == 0) {
10860 // Not existing yet, copy
10861 dst->id = src->id;
10862 dst->idx = src->idx;
10863 dst->max = src->max;
10864 dst->joblv = src->joblv;
10865 VECTOR_INIT(dst->need);
10866 if (VECTOR_LENGTH(src->need) > 0) {
10867 VECTOR_ENSURE(dst->need, VECTOR_LENGTH(src->need), 1);
10868 VECTOR_PUSHARRAY(dst->need, VECTOR_DATA(src->need), VECTOR_LENGTH(src->need));
10869 }
10870 } else {
10871 int l;
10872 // Already existing, merge
10873 if (src->max > dst->max)
10874 dst->max = src->max;
10875 dst->joblv = src->joblv;
10876 for (l = 0; l < VECTOR_LENGTH(src->need); l++) {
10877 int m;
10878 struct skill_tree_requirement *sreq = &VECTOR_INDEX(src->need, l);
10879 ARR_FIND(0, VECTOR_LENGTH(dst->need), m, VECTOR_INDEX(dst->need, m).id == sreq->id);
10880 if (m == VECTOR_LENGTH(dst->need)) {
10881 VECTOR_ENSURE(dst->need, 1, 1);
10882 VECTOR_PUSHCOPY(dst->need, sreq);
10883 } else {
10884 struct skill_tree_requirement *dreq = &VECTOR_INDEX(dst->need, m);
10885 dreq->lv = sreq->lv;
10886 }
10887 }
10888 }
10889 }
10890 }
10891 }
10892 if ((t = libconfig->setting_get_member(skt, "skills")) != NULL) {
10893 int j = 0;
10894 struct config_setting_t *sk = NULL;
10895 // Foreach skill
10896 while ((sk = libconfig->setting_get_elem(t, j++)) != NULL) {
10897 int skill_id, sk_idx;
10898 struct config_setting_t *rsk = NULL;
10899 const char *sk_name = config_setting_name(sk);
10900 struct skill_tree_entry *tree_entry = NULL;
10901
10902 if ((skill_id = skill->name2id(sk_name)) == 0) {
10903 ShowWarning("pc_read_skill_tree: unknown skill '%s' in '%s'\n", sk_name, job_name);
10904 continue;
10905 }
10906
10907 ARR_FIND(0, MAX_SKILL_TREE, sk_idx, pc->skill_tree[job_idx][sk_idx].id == 0 || pc->skill_tree[job_idx][sk_idx].id == skill_id);
10908 if (sk_idx == MAX_SKILL_TREE) {
10909 ShowWarning("pc_read_skill_tree: Unable to load skill %d (%s) into '%s's tree. Maximum number of skills per class has been reached.\n", skill_id, sk_name, job_name);
10910 continue;
10911 }
10912 tree_entry = &pc->skill_tree[job_idx][sk_idx];
10913
10914 if (tree_entry->id != 0 && !tree_entry->inherited) {
10915 ShowNotice("pc_read_skill_tree: Duplicate %d for '%s' (%d). Skipping.\n", skill_id, job_name, job_id);
10916 continue;
10917 }
10918 if (config_setting_is_group(sk)) {
10919 int i32 = 0;
10920 if (libconfig->setting_lookup_int(sk, "MaxLevel", &i32) && i32 > 0) {
10921 tree_entry->max = (unsigned char)i32;
10922 } else {
10923 ShowWarning("pc_read_skill_tree: missing MaxLevel for skill %d (%s) class '%s'. Skipping.\n", skill_id, sk_name, job_name);
10924 continue;
10925 }
10926 if (libconfig->setting_lookup_int(sk, "MinJobLevel", &i32) && i32 > 0) {
10927 tree_entry->joblv = (unsigned char)i32;
10928 } else if (!tree_entry->inherited) {
10929 tree_entry->joblv = 0;
10930 }
10931 } else {
10932 tree_entry->max = (unsigned char)libconfig->setting_get_int(sk);
10933 if (!tree_entry->inherited)
10934 tree_entry->joblv = 0;
10935 }
10936 if (!tree_entry->inherited) {
10937 tree_entry->id = skill_id;
10938 tree_entry->idx = skill->get_index(skill_id);
10939 VECTOR_INIT(tree_entry->need);
10940 }
10941
10942 if (config_setting_is_group(sk)) {
10943 int k = 0;
10944 // Foreach requirement
10945 while ((rsk = libconfig->setting_get_elem(sk, k++)) != NULL) {
10946 const char *rsk_name = config_setting_name(rsk);
10947 int rsk_id = skill->name2id(rsk_name);
10948 struct skill_tree_requirement *req = NULL;
10949 int l;
10950
10951 if (rsk_id == 0) {
10952 if (strcmp(rsk_name, "MaxLevel") != 0 && strcmp(rsk_name, "MinJobLevel") != 0)
10953 ShowWarning("pc_read_skill_tree: unknown requirement '%s' for '%s' in '%s'\n", rsk_name, sk_name, job_name);
10954 continue;
10955 }
10956 ARR_FIND(0, VECTOR_LENGTH(tree_entry->need), l, VECTOR_INDEX(tree_entry->need, l).id == rsk_id);
10957 if (l == VECTOR_LENGTH(tree_entry->need)) {
10958 VECTOR_ENSURE(tree_entry->need, 1, 1);
10959 VECTOR_PUSHZEROED(tree_entry->need);
10960 req = &VECTOR_LAST(tree_entry->need);
10961 req->id = rsk_id;
10962 req->idx = skill->get_index(rsk_id);
10963 } else {
10964 req = &VECTOR_INDEX(tree_entry->need, l);
10965 }
10966 req->lv = (unsigned char)libconfig->setting_get_int(rsk);
10967 }
10968 }
10969 }
10970 }
10971 }
10972
10973 libconfig->destroy(&skill_tree_conf);
10974
10975 /* lets update all players skill tree */
10976 iter = mapit_getallusers();
10977 for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter)))
10978 clif->skillinfoblock(sd);
10979 mapit->free(iter);
10980}
10981
10982/**
10983 * Clears the skill tree and frees any allocated memory.
10984 */
10985void pc_clear_skill_tree(void)
10986{
10987 int i;
10988 for (i = 0; i < CLASS_COUNT; i++) {
10989 int j;
10990 for (j = 0; j < MAX_SKILL_TREE; j++) {
10991 if (pc->skill_tree[i][j].id == 0)
10992 continue;
10993 VECTOR_CLEAR(pc->skill_tree[i][j].need);
10994 }
10995 }
10996 memset(pc->skill_tree, 0, sizeof(pc->skill_tree));
10997}
10998
10999bool pc_readdb_levelpenalty(char* fields[], int columns, int current) {
11000#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
11001 int type, race, diff;
11002
11003 nullpo_retr(false, fields);
11004 type = atoi(fields[0]);
11005 race = atoi(fields[1]);
11006 diff = atoi(fields[2]);
11007
11008 if( type != 1 && type != 2 ){
11009 ShowWarning("pc_readdb_levelpenalty: Invalid type %d specified.\n", type);
11010 return false;
11011 }
11012
11013 if (race < RC_FORMLESS || race > RC_MAX) {
11014 ShowWarning("pc_readdb_levelpenalty: Invalid race %d specified.\n", race);
11015 return false;
11016 }
11017
11018 diff = min(diff, MAX_LEVEL);
11019
11020 if( diff < 0 )
11021 diff = min(MAX_LEVEL + ( ~(diff) + 1 ), MAX_LEVEL*2);
11022
11023 pc->level_penalty[type][race][diff] = atoi(fields[3]);
11024#endif
11025 return true;
11026}
11027
11028/*==========================================
11029 * pc DB reading.
11030 * exp.txt - required experience values
11031 * skill_tree.txt - skill tree for every class
11032 * attr_fix.txt - elemental adjustment table
11033 *------------------------------------------*/
11034int pc_readdb(void) {
11035 int i,j,k;
11036 unsigned int count = 0;
11037 FILE *fp;
11038 char line[24000],*p;
11039
11040 //reset
11041 memset(pc->exp_table,0,sizeof(pc->exp_table));
11042 memset(pc->max_level,0,sizeof(pc->max_level));
11043
11044 sprintf(line, "%s/"DBPATH"exp.txt", map->db_path);
11045
11046 fp=fopen(line, "r");
11047 if(fp==NULL){
11048 ShowError("can't read %s\n", line);
11049 return 1;
11050 }
11051 while(fgets(line, sizeof(line), fp)) {
11052 int jobs[CLASS_COUNT], job_count, job, job_id;
11053 int type;
11054 int maxlv;
11055 char *split[4];
11056 if(line[0]=='/' && line[1]=='/')
11057 continue;
11058 if (pc_split_str(line,split,4) < 4)
11059 continue;
11060
11061 job_count = pc_split_atoi(split[1],jobs,':',CLASS_COUNT);
11062 if (job_count < 1)
11063 continue;
11064 job_id = jobs[0];
11065 if (!pc->db_checkid(job_id)) {
11066 ShowError("pc_readdb: Invalid job ID %d.\n", job_id);
11067 continue;
11068 }
11069 type = atoi(split[2]);
11070 if (type < 0 || type > 1) {
11071 ShowError("pc_readdb: Invalid type %d (must be 0 for base levels, 1 for job levels).\n", type);
11072 continue;
11073 }
11074 maxlv = atoi(split[0]);
11075 if (maxlv > MAX_LEVEL) {
11076 ShowWarning("pc_readdb: Specified max level %d for job %d is beyond server's limit (%d).\n ", maxlv, job_id, MAX_LEVEL);
11077 maxlv = MAX_LEVEL;
11078 }
11079 count++;
11080 job = jobs[0] = pc->class2idx(job_id);
11081 //We send one less and then one more because the last entry in the exp array should hold 0.
11082 pc->max_level[job][type] = pc_split_atoui(split[3], pc->exp_table[job][type],',',maxlv-1)+1;
11083 //Reverse check in case the array has a bunch of trailing zeros... [Skotlex]
11084 //The reasoning behind the -2 is this... if the max level is 5, then the array
11085 //should look like this:
11086 //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3.
11087 while ((i = pc->max_level[job][type]) >= 2 && pc->exp_table[job][type][i-2] <= 0)
11088 pc->max_level[job][type]--;
11089 if (pc->max_level[job][type] < maxlv) {
11090 ShowWarning("pc_readdb: Specified max %d for job %d, but that job's exp table only goes up to level %d.\n", maxlv, job_id, pc->max_level[job][type]);
11091 ShowInfo("Filling the missing values with the last exp entry.\n");
11092 //Fill the requested values with the last entry.
11093 i = (pc->max_level[job][type] <= 2 ? 0: pc->max_level[job][type]-2);
11094 for (; i+2 < maxlv; i++)
11095 pc->exp_table[job][type][i] = pc->exp_table[job][type][i-1];
11096 pc->max_level[job][type] = maxlv;
11097 }
11098 //ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]);
11099 for (i = 1; i < job_count; i++) {
11100 job_id = jobs[i];
11101 if (!pc->db_checkid(job_id)) {
11102 ShowError("pc_readdb: Invalid job ID %d.\n", job_id);
11103 continue;
11104 }
11105 job = pc->class2idx(job_id);
11106 memcpy(pc->exp_table[job][type], pc->exp_table[jobs[0]][type], sizeof(pc->exp_table[0][0]));
11107 pc->max_level[job][type] = maxlv;
11108 //ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]);
11109 }
11110 }
11111 fclose(fp);
11112 pc->validate_levels();
11113 ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"exp.txt");
11114 count = 0;
11115 // Reset and read skilltree
11116 pc->clear_skill_tree();
11117 pc->read_skill_tree();
11118#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
11119 sv->readdb(map->db_path, "re/level_penalty.txt", ',', 4, 4, -1, pc->readdb_levelpenalty);
11120 for( k=1; k < 3; k++ ){ // fill in the blanks
11121 for (j = RC_FORMLESS; j < RC_MAX; j++) {
11122 int tmp = 0;
11123 for( i = 0; i < MAX_LEVEL*2; i++ ){
11124 if( i == MAX_LEVEL+1 )
11125 tmp = pc->level_penalty[k][j][0];// reset
11126 if( pc->level_penalty[k][j][i] > 0 )
11127 tmp = pc->level_penalty[k][j][i];
11128 else
11129 pc->level_penalty[k][j][i] = tmp;
11130 }
11131 }
11132 }
11133#endif
11134
11135 // Reset then read attr_fix
11136 for(i=0;i<4;i++)
11137 for ( j = ELE_NEUTRAL; j<ELE_MAX; j++ )
11138 for ( k = ELE_NEUTRAL; k<ELE_MAX; k++ )
11139 battle->attr_fix_table[i][j][k]=100;
11140
11141 sprintf(line, "%s/"DBPATH"attr_fix.txt", map->db_path);
11142
11143 fp=fopen(line,"r");
11144 if(fp==NULL){
11145 ShowError("can't read %s\n", line);
11146 return 1;
11147 }
11148 while (fgets(line, sizeof(line), fp)) {
11149 char *split[10];
11150 int lv,n;
11151 if (line[0]=='/' && line[1]=='/')
11152 continue;
11153 for (j = 0, p = line; j < 3 && p != NULL; j++) {
11154 split[j] = p;
11155 p = strchr(p,',');
11156 if (p != NULL)
11157 *p++ = 0;
11158 }
11159 if (j < 2)
11160 continue;
11161
11162 lv=atoi(split[0]);
11163 n=atoi(split[1]);
11164 count++;
11165 for ( i = ELE_NEUTRAL; i<n && i<ELE_MAX; ) {
11166 if( !fgets(line, sizeof(line), fp) )
11167 break;
11168 if(line[0]=='/' && line[1]=='/')
11169 continue;
11170
11171 for (j = ELE_NEUTRAL, p = line; j < n && j < ELE_MAX && p != NULL; j++) {
11172 while (*p == ' ')
11173 p++;
11174 battle->attr_fix_table[lv-1][i][j]=atoi(p);
11175#ifndef RENEWAL
11176 if(battle_config.attr_recover == 0 && battle->attr_fix_table[lv-1][i][j] < 0)
11177 battle->attr_fix_table[lv-1][i][j] = 0;
11178#endif
11179 p=strchr(p,',');
11180 if (p != NULL)
11181 *p++ = 0;
11182 }
11183
11184 i++;
11185 }
11186 }
11187 fclose(fp);
11188 ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"attr_fix.txt");
11189 count = 0;
11190 // reset then read statspoint
11191 memset(pc->statp,0,sizeof(pc->statp));
11192 i=1;
11193
11194 sprintf(line, "%s/"DBPATH"statpoint.txt", map->db_path);
11195 fp=fopen(line,"r");
11196 if(fp == NULL){
11197 ShowWarning("Can't read '"CL_WHITE"%s"CL_RESET"'... Generating DB.\n",line);
11198 //return 1;
11199 } else {
11200 while(fgets(line, sizeof(line), fp))
11201 {
11202 int stat;
11203 if(line[0]=='/' && line[1]=='/')
11204 continue;
11205 if ((stat=(int)strtol(line,NULL,10))<0)
11206 stat=0;
11207 if (i > MAX_LEVEL)
11208 break;
11209 count++;
11210 pc->statp[i]=stat;
11211 i++;
11212 }
11213 fclose(fp);
11214
11215 ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"statpoint.txt");
11216 }
11217 // generate the remaining parts of the db if necessary
11218 k = battle_config.use_statpoint_table; //save setting
11219 battle_config.use_statpoint_table = 0; //temporarily disable to force pc->gets_status_point use default values
11220 pc->statp[0] = 45; // seed value
11221 for (; i <= MAX_LEVEL; i++)
11222 pc->statp[i] = pc->statp[i-1] + pc->gets_status_point(i-1);
11223 battle_config.use_statpoint_table = k; //restore setting
11224
11225 return 0;
11226}
11227
11228void pc_validate_levels(void) {
11229 int i;
11230 int j;
11231 for (i = 0; i < JOB_MAX; i++) {
11232 if (!pc->db_checkid(i)) continue;
11233 if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER)
11234 continue; //Classes that do not need exp tables.
11235 j = pc->class2idx(i);
11236 if (pc->max_level[j][0] == 0)
11237 ShowWarning("Class %s (%d) does not has a base exp table.\n", pc->job_name(i), i);
11238 if (pc->max_level[j][1] == 0)
11239 ShowWarning("Class %s (%d) does not has a job exp table.\n", pc->job_name(i), i);
11240 }
11241}
11242
11243void pc_itemcd_do(struct map_session_data *sd, bool load) {
11244 int i,cursor = 0;
11245 struct item_cd* cd = NULL;
11246
11247 nullpo_retv(sd);
11248 if( load ) {
11249 if( !(cd = idb_get(pc->itemcd_db, sd->status.char_id)) ) {
11250 // no skill cooldown is associated with this character
11251 return;
11252 }
11253 for(i = 0; i < MAX_ITEMDELAYS; i++) {
11254 if( cd->nameid[i] && DIFF_TICK(timer->gettick(),cd->tick[i]) < 0 ) {
11255 sd->item_delay[cursor].tick = cd->tick[i];
11256 sd->item_delay[cursor].nameid = cd->nameid[i];
11257 cursor++;
11258 }
11259 }
11260 idb_remove(pc->itemcd_db,sd->status.char_id);
11261 } else {
11262 if( !(cd = idb_get(pc->itemcd_db,sd->status.char_id)) ) {
11263 // create a new skill cooldown object for map storage
11264 CREATE( cd, struct item_cd, 1 );
11265 idb_put( pc->itemcd_db, sd->status.char_id, cd );
11266 }
11267 for(i = 0; i < MAX_ITEMDELAYS; i++) {
11268 if( sd->item_delay[i].nameid && DIFF_TICK(timer->gettick(),sd->item_delay[i].tick) < 0 ) {
11269 cd->tick[cursor] = sd->item_delay[i].tick;
11270 cd->nameid[cursor] = sd->item_delay[i].nameid;
11271 cursor++;
11272 }
11273 }
11274 }
11275 return;
11276}
11277
11278void pc_bank_deposit(struct map_session_data *sd, int money) {
11279 unsigned int limit_check;
11280
11281 nullpo_retv(sd);
11282 limit_check = money + sd->status.bank_vault;
11283
11284 if( money <= 0 || limit_check > MAX_BANK_ZENY ) {
11285 clif->bank_deposit(sd,BDA_OVERFLOW);
11286 return;
11287 } else if ( money > sd->status.zeny ) {
11288 clif->bank_deposit(sd,BDA_NO_MONEY);
11289 return;
11290 }
11291
11292 if( pc->payzeny(sd,money, LOG_TYPE_BANK, NULL) )
11293 clif->bank_deposit(sd,BDA_NO_MONEY);
11294 else {
11295 sd->status.bank_vault += money;
11296 if( map->save_settings&256 )
11297 chrif->save(sd,0);
11298 clif->bank_deposit(sd,BDA_SUCCESS);
11299 }
11300}
11301void pc_bank_withdraw(struct map_session_data *sd, int money) {
11302 unsigned int limit_check;
11303
11304 nullpo_retv(sd);
11305 limit_check = money + sd->status.zeny;
11306 if (money <= 0) {
11307 clif->bank_withdraw(sd,BWA_UNKNOWN_ERROR);
11308 return;
11309 } else if (money > sd->status.bank_vault) {
11310 clif->bank_withdraw(sd,BWA_NO_MONEY);
11311 return;
11312 } else if (limit_check > MAX_ZENY) {
11313 /* no official response for this scenario exists. */
11314 clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1482));
11315 return;
11316 }
11317
11318 if( pc->getzeny(sd,money, LOG_TYPE_BANK, NULL) )
11319 clif->bank_withdraw(sd,BWA_NO_MONEY);
11320 else {
11321 sd->status.bank_vault -= money;
11322 if( map->save_settings&256 )
11323 chrif->save(sd,0);
11324 clif->bank_withdraw(sd,BWA_SUCCESS);
11325 }
11326}
11327/* status change data arrived from char-server */
11328void pc_scdata_received(struct map_session_data *sd) {
11329 nullpo_retv(sd);
11330 pc->inventory_rentals(sd);
11331 clif->show_modifiers(sd);
11332
11333 if (sd->expiration_time != 0) { // don't display if it's unlimited or unknow value
11334 time_t exp_time = sd->expiration_time;
11335 char tmpstr[1024];
11336 strftime(tmpstr, sizeof(tmpstr) - 1, msg_sd(sd,501), localtime(&exp_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S."
11337 clif->wis_message(sd->fd, map->wisp_server_name, tmpstr, (int)strlen(tmpstr));
11338
11339 pc->expire_check(sd);
11340 }
11341
11342 if( sd->state.standalone ) {
11343 clif->pLoadEndAck(0,sd);
11344 pc->autotrade_populate(sd);
11345 pc->autotrade_start(sd);
11346 }
11347}
11348int pc_expiration_timer(int tid, int64 tick, int id, intptr_t data) {
11349 struct map_session_data *sd = map->id2sd(id);
11350
11351 if( !sd ) return 0;
11352
11353 sd->expiration_tid = INVALID_TIMER;
11354
11355 if( sd->fd )
11356 clif->authfail_fd(sd->fd,10);
11357
11358 map->quit(sd);
11359
11360 return 0;
11361}
11362/* This timer exists only when a character with an expire timer > 24h is online */
11363/* It loops through online players once an hour to check whether a new < 24h is available */
11364int pc_global_expiration_timer(int tid, int64 tick, int id, intptr_t data) {
11365 struct s_mapiterator* iter;
11366 struct map_session_data* sd;
11367
11368 iter = mapit_getallusers();
11369 for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
11370 if( sd->expiration_time )
11371 pc->expire_check(sd);
11372 }
11373 mapit->free(iter);
11374
11375 return 0;
11376}
11377void pc_expire_check(struct map_session_data *sd) {
11378 nullpo_retv(sd);
11379 /* ongoing timer */
11380 if( sd->expiration_tid != INVALID_TIMER )
11381 return;
11382
11383 /* not within the next 24h, enable the global check */
11384 if( sd->expiration_time > ( time(NULL) + ( ( 60 * 60 ) * 24 ) ) ) {
11385 /* global check not running, enable */
11386 if( pc->expiration_tid == INVALID_TIMER ) {
11387 /* starts in 1h, repeats every hour */
11388 pc->expiration_tid = timer->add_interval(timer->gettick() + ((1000*60)*60), pc->global_expiration_timer, 0, 0, ((1000*60)*60));
11389 }
11390 return;
11391 }
11392
11393 sd->expiration_tid = timer->add(timer->gettick() + (int64)(sd->expiration_time - time(NULL))*1000, pc->expiration_timer, sd->bl.id, 0);
11394}
11395/**
11396 * Loads autotraders
11397 ***/
11398void pc_autotrade_load(void)
11399{
11400 char *data;
11401
11402 if (SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `account_id`,`char_id`,`sex`,`title` FROM `%s`",map->autotrade_merchants_db))
11403 Sql_ShowDebug(map->mysql_handle);
11404
11405 while (SQL_SUCCESS == SQL->NextRow(map->mysql_handle)) {
11406 struct map_session_data *sd;
11407 int account_id, char_id;
11408 char title[MESSAGE_SIZE];
11409 unsigned char sex;
11410
11411 SQL->GetData(map->mysql_handle, 0, &data, NULL); account_id = atoi(data);
11412 SQL->GetData(map->mysql_handle, 1, &data, NULL); char_id = atoi(data);
11413 SQL->GetData(map->mysql_handle, 2, &data, NULL); sex = atoi(data);
11414 SQL->GetData(map->mysql_handle, 3, &data, NULL); safestrncpy(title, data, sizeof(title));
11415
11416 CREATE(sd, struct map_session_data, 1);
11417
11418 pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0);
11419
11420 safestrncpy(sd->message, title, MESSAGE_SIZE);
11421 sd->state.standalone = 1;
11422 sd->group = pcg->get_dummy_group();
11423
11424 chrif->authreq(sd,true);
11425 }
11426 SQL->FreeResult(map->mysql_handle);
11427}
11428/**
11429 * Loads vending data and sets it up, is triggered when char server data that pc_autotrade_load requested arrives
11430 **/
11431void pc_autotrade_start(struct map_session_data *sd) {
11432 unsigned int count = 0;
11433 int i;
11434 char *data;
11435
11436 nullpo_retv(sd);
11437 if (SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `itemkey`,`amount`,`price` FROM `%s` WHERE `char_id` = '%d'",map->autotrade_data_db,sd->status.char_id))
11438 Sql_ShowDebug(map->mysql_handle);
11439
11440 while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) {
11441 int itemkey, amount, price;
11442
11443 SQL->GetData(map->mysql_handle, 0, &data, NULL); itemkey = atoi(data);
11444 SQL->GetData(map->mysql_handle, 1, &data, NULL); amount = atoi(data);
11445 SQL->GetData(map->mysql_handle, 2, &data, NULL); price = atoi(data);
11446
11447 ARR_FIND(0, MAX_CART, i, sd->status.cart[i].id == itemkey);
11448 if( i != MAX_CART && itemdb_cantrade(&sd->status.cart[i], 0, 0) ) {
11449 if( amount > sd->status.cart[i].amount )
11450 amount = sd->status.cart[i].amount;
11451
11452 if( amount ) {
11453 sd->vending[count].index = i;
11454 sd->vending[count].amount = amount;
11455 sd->vending[count].value = cap_value(price, 0, (unsigned int)battle_config.vending_max_value);
11456
11457 count++;
11458 }
11459 }
11460 }
11461
11462 if( !count ) {
11463 pc->autotrade_update(sd,PAUC_REMOVE);
11464 map->quit(sd);
11465 } else {
11466 sd->state.autotrade = 1;
11467 sd->vender_id = ++vending->next_id;
11468 sd->vend_num = count;
11469 sd->state.vending = true;
11470 idb_put(vending->db, sd->status.char_id, sd);
11471 if( map->list[sd->bl.m].users )
11472 clif->showvendingboard(&sd->bl,sd->message,0);
11473 }
11474}
11475/**
11476 * Perform a autotrade action
11477 **/
11478void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update_action action) {
11479 int i;
11480
11481 nullpo_retv(sd);
11482 /* either way, this goes down */
11483 if( action != PAUC_START ) {
11484 if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'",map->autotrade_data_db,sd->status.char_id))
11485 Sql_ShowDebug(map->mysql_handle);
11486 }
11487
11488 switch( action ) {
11489 case PAUC_REMOVE:
11490 if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' LIMIT 1",map->autotrade_merchants_db,sd->status.char_id))
11491 Sql_ShowDebug(map->mysql_handle);
11492 break;
11493 case PAUC_START: {
11494 char title[MESSAGE_SIZE*2+1];
11495
11496 SQL->EscapeStringLen(map->mysql_handle, title, sd->message, strnlen(sd->message, MESSAGE_SIZE));
11497
11498 if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`account_id`,`char_id`,`sex`,`title`) VALUES ('%d','%d','%d','%s')",
11499 map->autotrade_merchants_db,
11500 sd->status.account_id,
11501 sd->status.char_id,
11502 sd->status.sex,
11503 title
11504 ))
11505 Sql_ShowDebug(map->mysql_handle);
11506 }
11507 FALLTHROUGH
11508 case PAUC_REFRESH:
11509 for( i = 0; i < sd->vend_num; i++ ) {
11510 if( sd->vending[i].amount == 0 )
11511 continue;
11512
11513 if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`char_id`,`itemkey`,`amount`,`price`) VALUES ('%d','%d','%d','%u')",
11514 map->autotrade_data_db,
11515 sd->status.char_id,
11516 sd->status.cart[sd->vending[i].index].id,
11517 sd->vending[i].amount,
11518 sd->vending[i].value
11519 ))
11520 Sql_ShowDebug(map->mysql_handle);
11521 }
11522 break;
11523 }
11524}
11525/**
11526 * Handles characters upon @autotrade usage
11527 **/
11528void pc_autotrade_prepare(struct map_session_data *sd) {
11529 struct autotrade_vending *data;
11530 int i, cursor = 0;
11531 int account_id, char_id;
11532 char title[MESSAGE_SIZE];
11533 unsigned char sex;
11534
11535 nullpo_retv(sd);
11536 CREATE(data, struct autotrade_vending, 1);
11537
11538 memcpy(data->vending, sd->vending, sizeof(sd->vending));
11539
11540 for(i = 0; i < sd->vend_num; i++) {
11541 if( sd->vending[i].amount ) {
11542 memcpy(&data->list[cursor],&sd->status.cart[sd->vending[i].index],sizeof(struct item));
11543 cursor++;
11544 }
11545 }
11546
11547 data->vend_num = (unsigned char)cursor;
11548
11549 idb_put(pc->at_db, sd->status.char_id, data);
11550
11551 account_id = sd->status.account_id;
11552 char_id = sd->status.char_id;
11553 sex = sd->status.sex;
11554 safestrncpy(title, sd->message, sizeof(title));
11555
11556 sd->npc_id = 0;
11557 sd->npc_shopid = 0;
11558 if (sd->st) {
11559 sd->st->state = END;
11560 sd->st = NULL;
11561 }
11562 map->quit(sd);
11563 chrif->auth_delete(account_id, char_id, ST_LOGOUT);
11564
11565 CREATE(sd, struct map_session_data, 1);
11566
11567 pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0);
11568
11569 safestrncpy(sd->message, title, MESSAGE_SIZE);
11570 sd->state.standalone = 1;
11571 sd->group = pcg->get_dummy_group();
11572
11573 chrif->authreq(sd,true);
11574}
11575/**
11576 * Prepares autotrade data from pc->at_db from a player that has already returned from char server
11577 **/
11578void pc_autotrade_populate(struct map_session_data *sd) {
11579 struct autotrade_vending *data;
11580 int i, j, k, cursor = 0;
11581
11582 nullpo_retv(sd);
11583 if( !(data = idb_get(pc->at_db,sd->status.char_id)) )
11584 return;
11585
11586 for(i = 0; i < data->vend_num; i++) {
11587 if( !data->vending[i].amount )
11588 continue;
11589
11590 for(j = 0; j < MAX_CART; j++) {
11591 if( !memcmp((char*)(&data->list[i]) + sizeof(data->list[0].id), (char*)(&sd->status.cart[j]) + sizeof(data->list[0].id), sizeof(struct item) - sizeof(data->list[0].id)) ) {
11592 if( cursor ) {
11593 ARR_FIND(0, cursor, k, sd->vending[k].index == j);
11594 if( k != cursor )
11595 continue;
11596 }
11597 break;
11598 }
11599 }
11600
11601 if( j != MAX_CART ) {
11602 sd->vending[cursor].index = j;
11603 sd->vending[cursor].amount = data->vending[i].amount;
11604 sd->vending[cursor].value = data->vending[i].value;
11605
11606 cursor++;
11607 }
11608 }
11609
11610 sd->vend_num = cursor;
11611
11612 pc->autotrade_update(sd,PAUC_START);
11613
11614 HPM->data_store_destroy(&data->hdata);
11615
11616 idb_remove(pc->at_db, sd->status.char_id);
11617}
11618
11619/**
11620 * @see DBApply
11621 */
11622int pc_autotrade_final(union DBKey key, struct DBData *data, va_list ap)
11623{
11624 struct autotrade_vending* at_v = DB->data2ptr(data);
11625 nullpo_ret(at_v);
11626 HPM->data_store_destroy(&at_v->hdata);
11627 return 0;
11628}
11629
11630void pc_update_idle_time(struct map_session_data* sd, enum e_battle_config_idletime type)
11631{
11632 nullpo_retv(sd);
11633 if (battle_config.idletime_criteria&type)
11634 sd->idletime = sockt->last_tick;
11635}
11636
11637//Checks if the given class value corresponds to a player class. [Skotlex]
11638//JOB_NOVICE isn't checked for class_ is supposed to be unsigned
11639bool pc_db_checkid(unsigned int class_)
11640{
11641 return class_ < JOB_MAX_BASIC
11642 || (class_ >= JOB_NOVICE_HIGH && class_ <= JOB_DARK_COLLECTOR )
11643 || (class_ >= JOB_RUNE_KNIGHT && class_ <= JOB_MECHANIC_T2 )
11644 || (class_ >= JOB_BABY_RUNE && class_ <= JOB_BABY_MECHANIC2 )
11645 || (class_ >= JOB_SUPER_NOVICE_E && class_ <= JOB_SUPER_BABY_E )
11646 || (class_ >= JOB_KAGEROU && class_ <= JOB_OBORO )
11647 || (class_ >= JOB_REBELLION && class_ < JOB_MAX );
11648}
11649
11650/**
11651 * checks if player have any kind of magnifier in inventory
11652 * @param sd map_session_data of Player
11653 * @return index of magnifer, INDEX_NOT_FOUND if it is not found
11654 */
11655int pc_have_magnifier(struct map_session_data *sd)
11656{
11657 int n;
11658 n = pc->search_inventory(sd, ITEMID_MAGNIFIER);
11659 if (n == INDEX_NOT_FOUND)
11660 n = pc->search_inventory(sd, ITEMID_NOVICE_MAGNIFIER);
11661 return n;
11662}
11663
11664/**
11665 * Verifies a chat message, searching for atcommands, checking if the sender
11666 * character can chat, and updating the idle timer.
11667 *
11668 * @param sd The sender character.
11669 * @param message The message text.
11670 * @return Whether the message is a valid chat message.
11671 */
11672bool pc_process_chat_message(struct map_session_data *sd, const char *message)
11673{
11674 nullpo_retr(false, sd);
11675 if (atcommand->exec(sd->fd, sd, message, true)) {
11676 return false;
11677 }
11678
11679 if (!pc->can_talk(sd)) {
11680 return false;
11681 }
11682
11683 if (battle_config.min_chat_delay != 0) {
11684 if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) {
11685 return false;
11686 }
11687 sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
11688 }
11689
11690 pc->update_idle_time(sd, BCIDLE_CHAT);
11691
11692 return true;
11693}
11694
11695/**
11696 * Checks a chat message, scanning for the Super Novice prayer sequence.
11697 *
11698 * If a match is found, the angel is invoked or the counter is incremented as
11699 * appropriate.
11700 *
11701 * @param sd The sender character.
11702 * @param message The message text.
11703 */
11704void pc_check_supernovice_call(struct map_session_data *sd, const char *message)
11705{
11706 unsigned int next = pc->nextbaseexp(sd);
11707 int percent = 0;
11708
11709 nullpo_retv(sd);
11710 nullpo_retv(message);
11711 if ((sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE)
11712 return;
11713 if (next == 0)
11714 next = pc->thisbaseexp(sd);
11715 if (next == 0)
11716 return;
11717
11718 // 0%, 10%, 20%, ...
11719 percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. );
11720 if ((battle_config.snovice_call_type != 0 || percent != 0) && (percent%100) == 0) {
11721 // 10.0%, 20.0%, ..., 90.0%
11722 switch (sd->state.snovice_call_flag) {
11723 case 0:
11724 if (strstr(message, msg_txt(1479))) // "Dear angel, can you hear my voice?"
11725 sd->state.snovice_call_flag = 1;
11726 break;
11727 case 1:
11728 {
11729 char buf[256];
11730 snprintf(buf, 256, msg_txt(1480), sd->status.name);
11731 if (strstr(message, buf)) // "I am %s Super Novice~"
11732 sd->state.snovice_call_flag = 2;
11733 }
11734 break;
11735 case 2:
11736 if (strstr(message, msg_txt(1481))) // "Help me out~ Please~ T_T"
11737 sd->state.snovice_call_flag = 3;
11738 break;
11739 case 3:
11740 sc_start(NULL, &sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
11741 clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions
11742 sd->state.snovice_call_flag = 0;
11743 break;
11744 }
11745 }
11746}
11747
11748void do_final_pc(void) {
11749 db_destroy(pc->itemcd_db);
11750 pc->at_db->destroy(pc->at_db,pc->autotrade_final);
11751
11752 pcg->final();
11753
11754 pc->clear_skill_tree();
11755
11756 ers_destroy(pc->sc_display_ers);
11757 ers_destroy(pc->num_reg_ers);
11758 ers_destroy(pc->str_reg_ers);
11759
11760 return;
11761}
11762
11763void do_init_pc(bool minimal) {
11764 if (minimal)
11765 return;
11766
11767 pc->itemcd_db = idb_alloc(DB_OPT_RELEASE_DATA);
11768 pc->at_db = idb_alloc(DB_OPT_RELEASE_DATA);
11769
11770 pc->readdb();
11771
11772 timer->add_func_list(pc->invincible_timer, "pc_invincible_timer");
11773 timer->add_func_list(pc->eventtimer, "pc_eventtimer");
11774 timer->add_func_list(pc->inventory_rental_end, "pc_inventory_rental_end");
11775 timer->add_func_list(pc->calc_pvprank_timer, "pc_calc_pvprank_timer");
11776 timer->add_func_list(pc->autosave, "pc_autosave");
11777 timer->add_func_list(pc->spiritball_timer, "pc_spiritball_timer");
11778 timer->add_func_list(pc->follow_timer, "pc_follow_timer");
11779 timer->add_func_list(pc->endautobonus, "pc_endautobonus");
11780 timer->add_func_list(pc->charm_timer, "pc_charm_timer");
11781 timer->add_func_list(pc->global_expiration_timer,"pc_global_expiration_timer");
11782 timer->add_func_list(pc->expiration_timer,"pc_expiration_timer");
11783
11784 timer->add(timer->gettick() + map->autosave_interval, pc->autosave, 0, 0);
11785
11786 // 0=day, 1=night [Yor]
11787 map->night_flag = battle_config.night_at_start ? 1 : 0;
11788
11789 if (battle_config.day_duration > 0 && battle_config.night_duration > 0) {
11790 int day_duration = battle_config.day_duration;
11791 int night_duration = battle_config.night_duration;
11792 // add night/day timer [Yor]
11793 timer->add_func_list(pc->map_day_timer, "pc_map_day_timer");
11794 timer->add_func_list(pc->map_night_timer, "pc_map_night_timer");
11795
11796 pc->day_timer_tid = timer->add_interval(timer->gettick() + (map->night_flag ? 0 : day_duration) + night_duration, pc->map_day_timer, 0, 0, day_duration + night_duration);
11797 pc->night_timer_tid = timer->add_interval(timer->gettick() + day_duration + (map->night_flag ? night_duration : 0), pc->map_night_timer, 0, 0, day_duration + night_duration);
11798 }
11799
11800 pcg->init();
11801
11802 pc->sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:sc_display_ers", ERS_OPT_FLEX_CHUNK);
11803 pc->num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.c::num_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
11804 pc->str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.c::str_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK);
11805
11806 ers_chunk_size(pc->sc_display_ers, 150);
11807 ers_chunk_size(pc->num_reg_ers, 300);
11808 ers_chunk_size(pc->str_reg_ers, 50);
11809}
11810/*=====================================
11811* Default Functions : pc.h
11812* Generated by HerculesInterfaceMaker
11813* created by Susu
11814*-------------------------------------*/
11815void pc_defaults(void) {
11816 const struct sg_data sg_info[MAX_PC_FEELHATE] = {
11817 { SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun },
11818 { SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon },
11819 { SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star }
11820 };
11821 unsigned int equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO, EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L };
11822
11823 pc = &pc_s;
11824
11825 /* vars */
11826 pc->at_db = NULL;
11827 pc->itemcd_db = NULL;
11828 /* */
11829 pc->day_timer_tid = INVALID_TIMER;
11830 pc->night_timer_tid = INVALID_TIMER;
11831
11832 // These macros are used instead of a sum of sizeof(), to ensure that padding won't interfere with our size, and code won't rot when adding more fields
11833 memset(ZEROED_BLOCK_POS(pc), 0, ZEROED_BLOCK_SIZE(pc));
11834
11835 /* */
11836 memcpy(pc->equip_pos, &equip_pos, sizeof(pc->equip_pos));
11837 /* */
11838 memcpy(pc->sg_info, sg_info, sizeof(pc->sg_info));
11839 /* */
11840 pc->sc_display_ers = NULL;
11841 /* */
11842 pc->expiration_tid = INVALID_TIMER;
11843 /* */
11844 pc->num_reg_ers = NULL;
11845 pc->str_reg_ers = NULL;
11846 /* */
11847 pc->reg_load = false;
11848 /* funcs */
11849 pc->init = do_init_pc;
11850 pc->final = do_final_pc;
11851
11852 pc->get_dummy_sd = pc_get_dummy_sd;
11853 pc->class2idx = pc_class2idx;
11854
11855 pc->can_use_command = pc_can_use_command;
11856 pc->set_group = pc_set_group;
11857 pc->should_log_commands = pc_should_log_commands;
11858
11859 pc->setrestartvalue = pc_setrestartvalue;
11860 pc->makesavestatus = pc_makesavestatus;
11861 pc->respawn = pc_respawn;
11862 pc->setnewpc = pc_setnewpc;
11863 pc->authok = pc_authok;
11864 pc->authfail = pc_authfail;
11865 pc->reg_received = pc_reg_received;
11866
11867 pc->isequip = pc_isequip;
11868 pc->equippoint = pc_equippoint;
11869 pc->setinventorydata = pc_setinventorydata;
11870
11871 pc->checkskill = pc_checkskill;
11872 pc->checkskill2 = pc_checkskill2;
11873 pc->checkallowskill = pc_checkallowskill;
11874 pc->checkequip = pc_checkequip;
11875
11876 pc->calc_skilltree = pc_calc_skilltree;
11877 pc->calc_skilltree_normalize_job = pc_calc_skilltree_normalize_job;
11878 pc->clean_skilltree = pc_clean_skilltree;
11879
11880 pc->setpos = pc_setpos;
11881 pc->setsavepoint = pc_setsavepoint;
11882 pc->randomwarp = pc_randomwarp;
11883 pc->memo = pc_memo;
11884
11885 pc->checkadditem = pc_checkadditem;
11886 pc->inventoryblank = pc_inventoryblank;
11887 pc->search_inventory = pc_search_inventory;
11888 pc->payzeny = pc_payzeny;
11889 pc->additem = pc_additem;
11890 pc->getzeny = pc_getzeny;
11891 pc->delitem = pc_delitem;
11892 // Special Shop System
11893 pc->paycash = pc_paycash;
11894 pc->getcash = pc_getcash;
11895
11896 pc->cart_additem = pc_cart_additem;
11897 pc->cart_delitem = pc_cart_delitem;
11898 pc->putitemtocart = pc_putitemtocart;
11899 pc->getitemfromcart = pc_getitemfromcart;
11900 pc->cartitem_amount = pc_cartitem_amount;
11901
11902 pc->takeitem = pc_takeitem;
11903 pc->dropitem = pc_dropitem;
11904
11905 pc->isequipped = pc_isequipped;
11906 pc->can_Adopt = pc_can_Adopt;
11907 pc->adoption = pc_adoption;
11908
11909 pc->updateweightstatus = pc_updateweightstatus;
11910
11911 pc->addautobonus = pc_addautobonus;
11912 pc->exeautobonus = pc_exeautobonus;
11913 pc->endautobonus = pc_endautobonus;
11914 pc->delautobonus = pc_delautobonus;
11915
11916 pc->bonus = pc_bonus;
11917 pc->bonus2 = pc_bonus2;
11918 pc->bonus3 = pc_bonus3;
11919 pc->bonus4 = pc_bonus4;
11920 pc->bonus5 = pc_bonus5;
11921 pc->skill = pc_skill;
11922
11923 pc->insert_card = pc_insert_card;
11924 pc->can_insert_card = pc_can_insert_card;
11925 pc->can_insert_card_into = pc_can_insert_card_into;
11926
11927 pc->steal_item = pc_steal_item;
11928 pc->steal_coin = pc_steal_coin;
11929
11930 pc->modifybuyvalue = pc_modifybuyvalue;
11931 pc->modifysellvalue = pc_modifysellvalue;
11932
11933 pc->follow = pc_follow; // [MouseJstr]
11934 pc->stop_following = pc_stop_following;
11935
11936 pc->maxbaselv = pc_maxbaselv;
11937 pc->maxjoblv = pc_maxjoblv;
11938 pc->checkbaselevelup = pc_checkbaselevelup;
11939 pc->checkjoblevelup = pc_checkjoblevelup;
11940 pc->gainexp = pc_gainexp;
11941 pc->nextbaseexp = pc_nextbaseexp;
11942 pc->thisbaseexp = pc_thisbaseexp;
11943 pc->nextjobexp = pc_nextjobexp;
11944 pc->thisjobexp = pc_thisjobexp;
11945 pc->gets_status_point = pc_gets_status_point;
11946 pc->need_status_point = pc_need_status_point;
11947 pc->maxparameterincrease = pc_maxparameterincrease;
11948 pc->statusup = pc_statusup;
11949 pc->statusup2 = pc_statusup2;
11950 pc->skillup = pc_skillup;
11951 pc->allskillup = pc_allskillup;
11952 pc->resetlvl = pc_resetlvl;
11953 pc->resetstate = pc_resetstate;
11954 pc->resetskill = pc_resetskill;
11955 pc->resetfeel = pc_resetfeel;
11956 pc->resethate = pc_resethate;
11957 pc->equipitem = pc_equipitem;
11958 pc->equipitem_pos = pc_equipitem_pos;
11959 pc->unequipitem = pc_unequipitem;
11960 pc->unequipitem_pos = pc_unequipitem_pos;
11961 pc->checkitem = pc_checkitem;
11962 pc->useitem = pc_useitem;
11963
11964 pc->skillatk_bonus = pc_skillatk_bonus;
11965 pc->skillheal_bonus = pc_skillheal_bonus;
11966 pc->skillheal2_bonus = pc_skillheal2_bonus;
11967
11968 pc->damage = pc_damage;
11969 pc->dead = pc_dead;
11970 pc->revive = pc_revive;
11971 pc->heal = pc_heal;
11972 pc->itemheal = pc_itemheal;
11973 pc->percentheal = pc_percentheal;
11974 pc->jobchange = pc_jobchange;
11975 pc->setoption = pc_setoption;
11976 pc->setcart = pc_setcart;
11977 pc->setfalcon = pc_setfalcon;
11978 pc->setridingpeco = pc_setridingpeco;
11979 pc->setmadogear = pc_setmadogear;
11980 pc->setridingdragon = pc_setridingdragon;
11981 pc->setridingwug = pc_setridingwug;
11982 pc->changelook = pc_changelook;
11983 pc->equiplookall = pc_equiplookall;
11984
11985 pc->readparam = pc_readparam;
11986 pc->setparam = pc_setparam;
11987 pc->readreg = pc_readreg;
11988 pc->setreg = pc_setreg;
11989 pc->readregstr = pc_readregstr;
11990 pc->setregstr = pc_setregstr;
11991 pc->readregistry = pc_readregistry;
11992 pc->setregistry = pc_setregistry;
11993 pc->readregistry_str = pc_readregistry_str;
11994 pc->setregistry_str = pc_setregistry_str;
11995
11996 pc->addeventtimer = pc_addeventtimer;
11997 pc->deleventtimer = pc_deleventtimer;
11998 pc->cleareventtimer = pc_cleareventtimer;
11999 pc->addeventtimercount = pc_addeventtimercount;
12000
12001 pc->calc_pvprank = pc_calc_pvprank;
12002 pc->calc_pvprank_timer = pc_calc_pvprank_timer;
12003
12004 pc->ismarried = pc_ismarried;
12005 pc->marriage = pc_marriage;
12006 pc->divorce = pc_divorce;
12007 pc->get_partner = pc_get_partner;
12008 pc->get_father = pc_get_father;
12009 pc->get_mother = pc_get_mother;
12010 pc->get_child = pc_get_child;
12011
12012 pc->bleeding = pc_bleeding;
12013 pc->regen = pc_regen;
12014
12015 pc->setstand = pc_setstand;
12016 pc->candrop = pc_candrop;
12017 pc->can_talk = pc_can_talk;
12018 pc->can_attack = pc_can_attack;
12019
12020 pc->jobid2mapid = pc_jobid2mapid; // Skotlex
12021 pc->mapid2jobid = pc_mapid2jobid; // Skotlex
12022
12023 pc->job_name = job_name;
12024
12025 pc->setinvincibletimer = pc_setinvincibletimer;
12026 pc->delinvincibletimer = pc_delinvincibletimer;
12027
12028 pc->addspiritball = pc_addspiritball;
12029 pc->delspiritball = pc_delspiritball;
12030 pc->addfame = pc_addfame;
12031 pc->famerank = pc_famerank;
12032 pc->set_hate_mob = pc_set_hate_mob;
12033 pc->getmaxspiritball = pc_getmaxspiritball;
12034
12035 pc->readdb = pc_readdb;
12036 pc->map_day_timer = map_day_timer; // by [yor]
12037 pc->map_night_timer = map_night_timer; // by [yor]
12038 // Rental System
12039 pc->inventory_rentals = pc_inventory_rentals;
12040 pc->inventory_rental_clear = pc_inventory_rental_clear;
12041 pc->inventory_rental_add = pc_inventory_rental_add;
12042
12043 pc->disguise = pc_disguise;
12044 pc->isautolooting = pc_isautolooting;
12045
12046 pc->overheat = pc_overheat;
12047 pc->banding = pc_banding;
12048
12049 pc->itemcd_do = pc_itemcd_do;
12050 pc->load_combo = pc_load_combo;
12051
12052 pc->add_charm = pc_add_charm;
12053 pc->del_charm = pc_del_charm;
12054
12055 pc->baselevelchanged = pc_baselevelchanged;
12056 pc->level_penalty_mod = pc_level_penalty_mod;
12057
12058 pc->calc_skillpoint = pc_calc_skillpoint;
12059
12060 pc->invincible_timer = pc_invincible_timer;
12061 pc->spiritball_timer = pc_spiritball_timer;
12062 pc->check_banding = pc_check_banding;
12063 pc->inventory_rental_end = pc_inventory_rental_end;
12064 pc->check_skilltree = pc_check_skilltree;
12065 pc->bonus_autospell = pc_bonus_autospell;
12066 pc->bonus_autospell_onskill = pc_bonus_autospell_onskill;
12067 pc->bonus_addeff = pc_bonus_addeff;
12068 pc->bonus_addeff_onskill = pc_bonus_addeff_onskill;
12069 pc->bonus_item_drop = pc_bonus_item_drop;
12070 pc->calcexp = pc_calcexp;
12071 pc->respawn_timer = pc_respawn_timer;
12072 pc->jobchange_killclone = jobchange_killclone;
12073 pc->getstat = pc_getstat;
12074 pc->setstat = pc_setstat;
12075 pc->eventtimer = pc_eventtimer;
12076 pc->daynight_timer_sub = pc_daynight_timer_sub;
12077 pc->charm_timer = pc_charm_timer;
12078 pc->readdb_levelpenalty = pc_readdb_levelpenalty;
12079 pc->autosave = pc_autosave;
12080 pc->follow_timer = pc_follow_timer;
12081 pc->read_skill_tree = pc_read_skill_tree;
12082 pc->clear_skill_tree = pc_clear_skill_tree;
12083 pc->isUseitem = pc_isUseitem;
12084 pc->show_steal = pc_show_steal;
12085 pc->checkcombo = pc_checkcombo;
12086 pc->calcweapontype = pc_calcweapontype;
12087 pc->removecombo = pc_removecombo;
12088
12089 pc->bank_withdraw = pc_bank_withdraw;
12090 pc->bank_deposit = pc_bank_deposit;
12091
12092 pc->rental_expire = pc_rental_expire;
12093 pc->scdata_received = pc_scdata_received;
12094
12095 pc->bound_clear = pc_bound_clear;
12096
12097 pc->expiration_timer = pc_expiration_timer;
12098 pc->global_expiration_timer = pc_global_expiration_timer;
12099 pc->expire_check = pc_expire_check;
12100 pc->db_checkid = pc_db_checkid;
12101 pc->validate_levels = pc_validate_levels;
12102
12103 pc->check_supernovice_call = pc_check_supernovice_call;
12104 pc->process_chat_message = pc_process_chat_message;
12105
12106 /**
12107 * Autotrade persistency [Ind/Hercules <3]
12108 **/
12109 pc->autotrade_load = pc_autotrade_load;
12110 pc->autotrade_update = pc_autotrade_update;
12111 pc->autotrade_start = pc_autotrade_start;
12112 pc->autotrade_prepare = pc_autotrade_prepare;
12113 pc->autotrade_populate = pc_autotrade_populate;
12114 pc->autotrade_final = pc_autotrade_final;
12115
12116 pc->check_job_name = pc_check_job_name;
12117 pc->update_idle_time = pc_update_idle_time;
12118
12119 pc->have_magnifier = pc_have_magnifier;
12120}