diff options
Diffstat (limited to 'src/map/pc.c')
-rw-r--r-- | src/map/pc.c | 1559 |
1 files changed, 993 insertions, 566 deletions
diff --git a/src/map/pc.c b/src/map/pc.c index 8d1df71a9..2303a83ca 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -63,6 +63,7 @@ #include "common/random.h" #include "common/showmsg.h" #include "common/socket.h" +#include "common/sql.h" #include "common/strlib.h" // safestrncpy() #include "common/sysinfo.h" #include "common/timer.h" @@ -79,10 +80,13 @@ struct pc_interface *pc; //Converts a class to its array index for CLASS_COUNT defined arrays. //Note that it does not do a validity check for speed purposes, where parsing //player input make sure to use a pc->db_checkid first! -int pc_class2idx(int class_) { - if (class_ >= JOB_NOVICE_HIGH) - return class_- JOB_NOVICE_HIGH+JOB_MAX_BASIC; - return class_; +int pc_class2idx(int class) +{ + if (class >= JOB_NOVICE_HIGH) { + class += - JOB_NOVICE_HIGH + JOB_MAX_BASIC; + } + Assert_ret(class >= 0 && class < CLASS_COUNT); + return class; } /** @@ -108,6 +112,7 @@ struct map_session_data* pc_get_dummy_sd(void) int pc_set_group(struct map_session_data *sd, int group_id) { GroupSettings *group = pcg->id2group(group_id); + nullpo_retr(1, sd); if (group == NULL) return 1; sd->group_id = group_id; @@ -120,6 +125,7 @@ int pc_set_group(struct map_session_data *sd, int group_id) */ bool pc_should_log_commands(struct map_session_data *sd) { + nullpo_retr(true, sd); return pcg->should_log_commands(sd->group); } @@ -140,7 +146,8 @@ int pc_invincible_timer(int tid, int64 tick, int id, intptr_t data) return 0; } -void pc_setinvincibletimer(struct map_session_data* sd, int val) { +void pc_setinvincibletimer(struct map_session_data* sd, int val) +{ nullpo_retv(sd); val += map->list[sd->bl.m].invincible_time_inc; @@ -241,7 +248,7 @@ int pc_addspiritball(struct map_session_data *sd,int interval,int max) memmove(sd->spirit_timer+i+1, sd->spirit_timer+i, (sd->spiritball-i)*sizeof(int)); sd->spirit_timer[i] = tid; sd->spiritball++; - if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD ) + if ((sd->job & MAPID_THIRDMASK) == MAPID_ROYAL_GUARD) clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); @@ -280,7 +287,7 @@ int pc_delspiritball(struct map_session_data *sd,int count,int type) } if(!type) { - if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD ) + if ((sd->job & MAPID_THIRDMASK) == MAPID_ROYAL_GUARD) clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); @@ -380,52 +387,108 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { return c; } -// Increases a player's fame points and displays a notice to him -void pc_addfame(struct map_session_data *sd,int count) +/** + * Increases a player's fame points and displays a notice to them. + * + * If the character's job class doesn't allow the specified rank type, nothing + * happens and the request is ignored. + * + * @param sd The target character. + * @param type The fame list type (@see enum fame_list_type). + * @param count The amount of points to add. + */ +void pc_addfame(struct map_session_data *sd, int ranktype, int count) { - int ranktype = -1; nullpo_retv(sd); + + switch (ranktype) { + case RANKTYPE_BLACKSMITH: + if ((sd->job & MAPID_UPPERMASK) != MAPID_BLACKSMITH) + return; + break; + case RANKTYPE_ALCHEMIST: + if ((sd->job & MAPID_UPPERMASK) != MAPID_ALCHEMIST) + return; + break; + case RANKTYPE_TAEKWON: + if ((sd->job & MAPID_UPPERMASK) != MAPID_TAEKWON) + return; + break; + case RANKTYPE_PK: + // Not supported + FALLTHROUGH + default: + Assert_retv(0); + } + sd->status.fame += count; - if(sd->status.fame > MAX_FAME) + if (sd->status.fame > MAX_FAME) sd->status.fame = MAX_FAME; - switch(sd->class_&MAPID_UPPERMASK){ - case MAPID_BLACKSMITH: ranktype = RANKTYPE_BLACKSMITH; break; - case MAPID_ALCHEMIST: ranktype = RANKTYPE_ALCHEMIST; break; - case MAPID_TAEKWON: ranktype = RANKTYPE_TAEKWON; break; - } + clif->update_rankingpoint(sd, ranktype, count); chrif->updatefamelist(sd); } -// Check whether a player ID is in the fame rankers' list of its job, returns his/her position if so, 0 else -unsigned char pc_famerank(int char_id, int job) +/** + * Returns a character's rank in the specified fame list. + * + * @param char_id The character ID. + * @param ranktype The rank list type (@see enum fame_list_type). + * @return The rank position (1-based index) + * @retval 0 if the character isn't in the specified list. + */ +int pc_fame_rank(int char_id, int ranktype) { int i; - switch(job){ - case MAPID_BLACKSMITH: // Blacksmith - for(i = 0; i < MAX_FAME_LIST; i++){ - if(pc->smith_fame_list[i].id == char_id) - return i + 1; - } - break; - case MAPID_ALCHEMIST: // Alchemist - for(i = 0; i < MAX_FAME_LIST; i++){ - if(pc->chemist_fame_list[i].id == char_id) - return i + 1; - } - break; - case MAPID_TAEKWON: // Taekwon - for(i = 0; i < MAX_FAME_LIST; i++){ - if(pc->taekwon_fame_list[i].id == char_id) - return i + 1; - } - break; + switch (ranktype) { + case RANKTYPE_BLACKSMITH: + for (i = 0; i < MAX_FAME_LIST; i++) { + if (pc->smith_fame_list[i].id == char_id) + return i + 1; + } + break; + case RANKTYPE_ALCHEMIST: + for (i = 0; i < MAX_FAME_LIST; i++) { + if (pc->chemist_fame_list[i].id == char_id) + return i + 1; + } + break; + case RANKTYPE_TAEKWON: + for (i = 0; i < MAX_FAME_LIST; i++) { + if (pc->taekwon_fame_list[i].id == char_id) + return i + 1; + } + break; + case RANKTYPE_PK: // Not implemented + FALLTHROUGH + default: + Assert_ret(0); } return 0; } +/** + * Returns the appropriate fame list type for the given job. + * + * @param job_mapid The job (in MapID format) + * @return the appropriate fame list type (@see enum fame_list_type). + * @retval RANKTYPE_UNKNOWN if no appropriate type exists. + */ +int pc_famelist_type(uint16 job_mapid) { + switch (job_mapid & MAPID_UPPERMASK) { + case MAPID_BLACKSMITH: + return RANKTYPE_BLACKSMITH; + case MAPID_ALCHEMIST: + return RANKTYPE_ALCHEMIST; + case MAPID_TAEKWON: + return RANKTYPE_TAEKWON; + default: + return RANKTYPE_UNKNOWN; + } +} + int pc_setrestartvalue(struct map_session_data *sd,int type) { struct status_data *st, *bst; nullpo_ret(sd); @@ -465,6 +528,7 @@ int pc_inventory_rental_end(int tid, int64 tick, int id, intptr_t data) { int pc_inventory_rental_clear(struct map_session_data *sd) { + nullpo_ret(sd); if( sd->rental_timer != INVALID_TIMER ) { timer->delete(sd->rental_timer, pc->inventory_rental_end); @@ -475,11 +539,15 @@ int pc_inventory_rental_clear(struct map_session_data *sd) } /* assumes i is valid (from default areas where it is called, it is) */ void pc_rental_expire(struct map_session_data *sd, int i) { - short nameid = sd->status.inventory[i].nameid; + short nameid; + + nullpo_retv(sd); + Assert_retv(i >= 0 && i < MAX_INVENTORY); + nameid = sd->status.inventory[i].nameid; /* Soon to be dropped, we got plans to integrate it with item db */ switch( nameid ) { - case ITEMID_REINS_OF_MOUNT: + case ITEMID_BOARDING_HALTER: status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); break; case ITEMID_LOVE_ANGEL: @@ -539,13 +607,14 @@ void pc_rental_expire(struct map_session_data *sd, int i) { } clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_RENTAL); } void pc_inventory_rentals(struct map_session_data *sd) { int i, c = 0; int64 expire_tick, next_tick = INT64_MAX; + nullpo_retv(sd); for( i = 0; i < MAX_INVENTORY; i++ ) { // Check for Rentals on Inventory if( sd->status.inventory[i].nameid == 0 ) @@ -672,10 +741,12 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo sd->client_tick = client_tick; sd->state.active = 0; //to be set to 1 after player is fully authed and loaded. sd->bl.type = BL_PC; - sd->canlog_tick = timer->gettick(); + if (battle_config.prevent_logout_trigger & PLT_LOGIN) + sd->canlog_tick = timer->gettick(); //Required to prevent homunculus copuing a base speed of 0. sd->battle_status.speed = sd->base_status.speed = DEFAULT_WALK_SPEED; sd->state.warp_clean = 1; + sd->catch_target_class = -1; return 0; } @@ -684,6 +755,7 @@ int pc_equippoint(struct map_session_data *sd,int n) int ep = 0; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); if(!sd->inventory_data[n]) return 0; @@ -697,8 +769,8 @@ int pc_equippoint(struct map_session_data *sd,int n) || sd->inventory_data[n]->look == W_1HAXE ) { if (pc->checkskill(sd,AS_LEFT) > 0 - || (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN - || (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO + || (sd->job & MAPID_UPPERMASK) == MAPID_ASSASSIN + || (sd->job & MAPID_UPPERMASK) == MAPID_KAGEROUOBORO ) { //Kagerou and Oboro can dual wield daggers. [Rytech] if( ep == EQP_HAND_R ) @@ -810,6 +882,7 @@ bool pc_isequipped(struct map_session_data *sd, int nameid) { int i, j; + nullpo_retr(false, sd); for (i = 0; i < EQI_MAX; i++) { int index = sd->equip_index[i]; if( index < 0 ) continue; @@ -872,7 +945,7 @@ bool pc_can_Adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd return false; } - if( !( ( b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF ) || b_sd->status.class_ == JOB_SUPER_NOVICE ) ) + if (!(b_sd->status.class >= JOB_NOVICE && b_sd->status.class <= JOB_THIEF) && b_sd->status.class != JOB_SUPER_NOVICE) return false; return true; @@ -883,19 +956,20 @@ bool pc_can_Adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd *------------------------------------------*/ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd) { - int job, joblevel; + int class, joblevel; unsigned int jobexp; if( !pc->can_Adopt(p1_sd, p2_sd, b_sd) ) return false; + nullpo_retr(false, b_sd); // Preserve current job levels and progress joblevel = b_sd->status.job_level; jobexp = b_sd->status.job_exp; - job = pc->mapid2jobid(b_sd->class_|JOBL_BABY, b_sd->status.sex); - if( job != -1 && !pc->jobchange(b_sd, job, 0) ) - { // Success, proceed to configure parents and baby skills + class = pc->mapid2jobid(b_sd->job | JOBL_BABY, b_sd->status.sex); + if (class != -1 && !pc->jobchange(b_sd, class, 0)) { + // Success, proceed to configure parents and baby skills p1_sd->status.child = b_sd->status.char_id; p2_sd->status.child = b_sd->status.char_id; b_sd->status.father = p1_sd->status.char_id; @@ -944,11 +1018,11 @@ int pc_isequip(struct map_session_data *sd,int n) if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT)) return 1; - if (item->elv && sd->status.base_level < (unsigned int)item->elv) { + if (item->elv && sd->status.base_level < item->elv) { clif->msgtable(sd, MSG_ITEM_CANT_EQUIP_LVL); return 0; } - if (item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) { + if (item->elvmax && sd->status.base_level > item->elvmax) { clif->msgtable(sd, MSG_ITEM_CANT_EQUIP_LVL); return 0; } @@ -956,12 +1030,11 @@ int pc_isequip(struct map_session_data *sd,int n) return 0; if ( item->equip & EQP_AMMO ) { - if ( (sd->state.active && !pc_iscarton(sd)) // check if sc data is already loaded. - && (sd->status.class_ == JOB_GENETIC_T || sd->status.class_ == JOB_GENETIC) ) { + if (sd->state.active && !pc_iscarton(sd) && (sd->job & MAPID_THIRDMASK) == MAPID_GENETIC) { // check if sc data is already loaded. clif->msgtable(sd, MSG_ITEM_NEED_CART); return 0; } - if ( !pc_ismadogear(sd) && (sd->status.class_ == JOB_MECHANIC_T || sd->status.class_ == JOB_MECHANIC) ) { + if (!pc_ismadogear(sd) && (sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) { clif->msgtable(sd, MSG_ITEM_NEED_MADO); return 0; } @@ -998,14 +1071,26 @@ int pc_isequip(struct map_session_data *sd,int n) } } //Not equipable by class. [Skotlex] - if (!(1<<(sd->class_&MAPID_BASEMASK)&item->class_base[(sd->class_&JOBL_2_1)?1:((sd->class_&JOBL_2_2)?2:0)])) + if (((1ULL<<(sd->job & MAPID_BASEMASK)) & item->class_base[(sd->job & JOBL_2_1) != 0 ? 1 : ((sd->job & JOBL_2_2) != 0 ? 2 : 0)]) == 0) return 0; //Not usable by upper class. [Inkfish] while( 1 ) { - if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; - if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; - if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY ) break; - if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD ) break; + if ((item->class_upper & ITEMUPPER_NORMAL) != 0) { + if ((sd->job & (JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) == 0) + break; + } + if ((item->class_upper & ITEMUPPER_UPPER) != 0) { + if ((sd->job & (JOBL_UPPER|JOBL_THIRD)) != 0) + break; + } + if ((item->class_upper & ITEMUPPER_BABY) != 0) { + if ((sd->job & JOBL_BABY) != 0) + break; + } + if ((item->class_upper & ITEMUPPER_THIRD) != 0) { + if ((sd->job & JOBL_THIRD) != 0) + break; + } return 0; } @@ -1033,10 +1118,14 @@ int pc_isequip(struct map_session_data *sd,int n) * No problem with the session id * set the status that has been sent from char server *------------------------------------------*/ -bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers) { +bool 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) +{ int i; int64 tick = timer->gettick(); - uint32 ip = sockt->session[sd->fd]->client_addr; + uint32 ip; + + nullpo_retr(false, sd); + ip = sockt->session[sd->fd]->client_addr; sd->login_id2 = login_id2; @@ -1055,13 +1144,16 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim } //Set the map-server used job id. [Skotlex] - i = pc->jobid2mapid(sd->status.class_); - if (i == -1) { //Invalid class? - 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); - sd->status.class_ = JOB_NOVICE; - sd->class_ = MAPID_NOVICE; - } else - sd->class_ = i; + { + int job = pc->jobid2mapid(sd->status.class); + if (job == -1) { + 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); + sd->status.class = JOB_NOVICE; + sd->job = MAPID_NOVICE; + } else { + sd->job = job; + } + } // Checks and fixes to character status data, that are required // in case of configuration change or stuff, which cannot be @@ -1142,7 +1234,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->sc.option = sd->status.option; //This is the actual option used in battle. //Set here because we need the inventory data for weapon sprite parsing. - status->set_viewdata(&sd->bl, sd->status.class_); + status->set_viewdata(&sd->bl, sd->status.class); unit->dataset(&sd->bl); sd->guild_x = -1; @@ -1159,13 +1251,14 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->bg_queue.type = 0; VECTOR_INIT(sd->script_queues); + VECTOR_INIT(sd->storage.item); // initialize storage item vector. sd->state.dialog = 0; sd->delayed_damage = 0; - if( battle_config.item_check ) - sd->state.itemcheck = 1; + if (battle->bc->item_check != PCCHECKITEM_NONE) // Check and flag items for inspection. + sd->itemcheck = (enum pc_checkitem_types) battle->bc->item_check; // Event Timers for( i = 0; i < MAX_EVENTTIMER; i++ ) @@ -1212,7 +1305,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim //display login notice ShowInfo("'"CL_WHITE"%s"CL_RESET"' logged in." " (AID/CID: '"CL_WHITE"%d/%d"CL_RESET"'," - " IP: '"CL_WHITE"%d.%d.%d.%d"CL_RESET"'," + " IP: '"CL_WHITE"%u.%u.%u.%u"CL_RESET"'," " Group '"CL_WHITE"%d"CL_RESET"').\n", sd->status.name, sd->status.account_id, sd->status.char_id, CONVIP(ip), sd->group_id); @@ -1266,6 +1359,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim *------------------------------------------*/ void pc_authfail(struct map_session_data *sd) { + nullpo_retv(sd); clif->authfail_fd(sd->fd, 0); return; } @@ -1303,6 +1397,7 @@ int pc_reg_received(struct map_session_data *sd) { int i, idx = 0; + nullpo_ret(sd); sd->vars_ok = true; sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level")); @@ -1316,7 +1411,7 @@ int pc_reg_received(struct map_session_data *sd) // Cooking Exp sd->cook_mastery = pc_readglobalreg(sd,script->add_str("COOK_MASTERY")); - if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) { + if ((sd->job & MAPID_BASEMASK) == MAPID_TAEKWON) { // Better check for class rather than skill to prevent "skill resets" from unsetting this sd->mission_mobid = pc_readglobalreg(sd,script->add_str("TK_MISSION_ID")); sd->mission_count = pc_readglobalreg(sd,script->add_str("TK_MISSION_COUNT")); @@ -1389,6 +1484,9 @@ int pc_reg_received(struct map_session_data *sd) status_calc_pc(sd,SCO_FIRST|SCO_FORCE); chrif->scdata_request(sd->status.account_id, sd->status.char_id); + // Storage Request + intif->request_account_storage(sd); + intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox intif->request_questlog(sd); @@ -1398,7 +1496,7 @@ int pc_reg_received(struct map_session_data *sd) } if (pc_isinvisible(sd)) { - sd->vd.class_ = INVISIBLE_CLASS; + sd->vd.class = INVISIBLE_CLASS; clif->message(sd->fd, msg_sd(sd,11)); // Invisible: On // decrement the number of pvp players on the map map->list[sd->bl.m].users_pvp--; @@ -1445,17 +1543,17 @@ int pc_calc_skillpoint(struct map_session_data* sd) { int pc_calc_skilltree(struct map_session_data *sd) { int i,id=0,flag; - int c=0; + int class = 0, classidx = 0; nullpo_ret(sd); i = pc->calc_skilltree_normalize_job(sd); - c = pc->mapid2jobid(i, sd->status.sex); - if( c == -1 ) - { //Unable to normalize job?? + class = pc->mapid2jobid(i, sd->status.sex); + if (class == -1) { + //Unable to normalize job?? 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); return 1; } - c = pc->class2idx(c); + classidx = pc->class2idx(class); for( i = 0; i < MAX_SKILL; i++ ) { if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these @@ -1464,10 +1562,10 @@ int pc_calc_skilltree(struct map_session_data *sd) if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) { switch( skill->dbs->db[i].nameid ) { case NV_TRICKDEAD: - if( (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) { - sd->status.skill[i].id = 0; - sd->status.skill[i].lv = 0; - sd->status.skill[i].flag = 0; + if ((sd->job & MAPID_UPPERMASK) != MAPID_NOVICE) { + sd->status.skill[i].id = 0; + sd->status.skill[i].lv = 0; + sd->status.skill[i].flag = 0; } break; } @@ -1537,16 +1635,16 @@ int pc_calc_skilltree(struct map_session_data *sd) do { flag = 0; - for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++) { - int idx = pc->skill_tree[c][i].idx; + for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[classidx][i].id) > 0; i++) { + int idx = pc->skill_tree[classidx][i].idx; bool satisfied = true; if (sd->status.skill[idx].id > 0) continue; //Skill already known. if (!battle_config.skillfree) { int j; - for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[c][i].need); j++) { - struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[c][i].need, j); + for (j = 0; j < VECTOR_LENGTH(pc->skill_tree[classidx][i].need); j++) { + struct skill_tree_requirement *req = &VECTOR_INDEX(pc->skill_tree[classidx][i].need, j); int level; if (sd->status.skill[req->idx].id == 0 || sd->status.skill[req->idx].flag == SKILL_FLAG_TEMPORARY @@ -1561,8 +1659,8 @@ int pc_calc_skilltree(struct map_session_data *sd) break; } } - if (sd->status.job_level < pc->skill_tree[c][i].joblv) { - int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree + if (sd->status.job_level < (int)pc->skill_tree[classidx][i].joblv) { + int jobid = pc->mapid2jobid(sd->job, sd->status.sex); // need to get its own skilltree if (jobid > -1) { if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited) satisfied = false; // job level requirement wasn't satisfied @@ -1593,16 +1691,17 @@ int pc_calc_skilltree(struct map_session_data *sd) } while(flag); // - 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) ) - { - /* Taekwon Ranger Bonus Skill Tree + if (classidx > 0 && (sd->job & MAPID_UPPERMASK) == MAPID_TAEKWON + && sd->status.base_level >= 90 && sd->status.skill_point == 0 + && pc->fame_rank(sd->status.char_id, RANKTYPE_TAEKWON) > 0) { + /* Taekwon Ranker Bonus Skill Tree ============================================ - Grant All Taekwon Tree, but only as Bonus Skills in case they drop from ranking. - (c > 0) to avoid grant Novice Skill Tree in case of Skill Reset (need more logic) - (sd->status.skill_point == 0) to wait until all skill points are asigned to avoid problems with Job Change quest. */ - for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { - int idx = pc->skill_tree[c][i].idx; + for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[classidx][i].id) > 0; i++) { + int idx = pc->skill_tree[classidx][i].idx; if( (skill->dbs->db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) continue; //Do not include Quest/Wedding skills. @@ -1613,7 +1712,7 @@ int pc_calc_skilltree(struct map_session_data *sd) sd->status.skill[idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[idx].lv; // Remember original level } - sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_); + sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class); } } @@ -1629,6 +1728,7 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) if(battle_config.skillfree) return; //Function serves no purpose if this is set + nullpo_retv(sd); i = pc->calc_skilltree_normalize_job(sd); c = pc->mapid2jobid(i, sd->status.sex); if (c == -1) { //Unable to normalize job?? @@ -1664,8 +1764,8 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) if (!satisfied) continue; - if (sd->status.job_level < pc->skill_tree[c][i].joblv) { - int jobid = pc->mapid2jobid(sd->class_, sd->status.sex); // need to get its own skilltree + if (sd->status.job_level < (int)pc->skill_tree[c][i].joblv) { + int jobid = pc->mapid2jobid(sd->job, sd->status.sex); // need to get its own skilltree if (jobid > -1) { if (!pc->skill_tree[pc->class2idx(jobid)][i].inherited) continue; @@ -1694,6 +1794,7 @@ void pc_check_skilltree(struct map_session_data *sd, int skill_id) int pc_clean_skilltree(struct map_session_data *sd) { int i; + nullpo_ret(sd); for (i = 0; i < MAX_SKILL; i++){ if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED) { sd->status.skill[i].id = 0; @@ -1711,10 +1812,12 @@ int pc_clean_skilltree(struct map_session_data *sd) int pc_calc_skilltree_normalize_job(struct map_session_data *sd) { int skill_point, novice_skills; - int c = sd->class_; + uint16 job; + nullpo_ret(sd); + job = sd->job; if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) - return c; + return job; skill_point = pc->calc_skillpoint(sd); @@ -1722,62 +1825,57 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) sd->sktree.second = sd->sktree.third = 0; - // limit 1st class and above to novice job levels - if(skill_point < novice_skills) { - c = MAPID_NOVICE; - } - // limit 2nd class and above to first class job levels (super novices are exempt) - else if ((sd->class_&JOBL_2) && (sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) - { + if (skill_point < novice_skills && (sd->job & MAPID_BASEMASK) != MAPID_SUMMONER) { + // limit 1st class and above to novice job levels + job = MAPID_NOVICE; + } else if ((sd->job & JOBL_2) != 0 && (sd->job & MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) { + // limit 2nd class and above to first class job levels (super novices are exempt) // regenerate change_level_2nd - if (!sd->change_level_2nd) - { - if (sd->class_&JOBL_THIRD) - { + if (sd->change_level_2nd == 0) { + if ((sd->job & JOBL_THIRD) != 0) { // if neither 2nd nor 3rd jobchange levels are known, we have to assume a default for 2nd - if (!sd->change_level_3rd) - sd->change_level_2nd = pc->max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1]; - else + if (sd->change_level_3rd == 0) { + sd->change_level_2nd = pc->max_level[pc->class2idx(pc->mapid2jobid(sd->job & MAPID_UPPERMASK, sd->status.sex))][1]; + } else { sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - (sd->status.job_level - 1) - (sd->change_level_3rd - 1) - novice_skills; - } - else - { + } + } else { sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - (sd->status.job_level - 1) - novice_skills; } - pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd); + pc_setglobalreg(sd, script->add_str("jobchange_level"), sd->change_level_2nd); } if (skill_point < novice_skills + (sd->change_level_2nd - 1)) { - c &= MAPID_BASEMASK; + job &= MAPID_BASEMASK; sd->sktree.second = ( novice_skills + (sd->change_level_2nd - 1) ) - skill_point; - } else if(sd->class_&JOBL_THIRD) { // limit 3rd class to 2nd class/trans job levels + } else if ((sd->job & JOBL_THIRD) != 0) { // limit 3rd class to 2nd class/trans job levels // regenerate change_level_3rd - if (!sd->change_level_3rd) { + if (sd->change_level_3rd == 0) { sd->change_level_3rd = 1 + skill_point + sd->status.skill_point - (sd->status.job_level - 1) - (sd->change_level_2nd - 1) - novice_skills; - pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); + pc_setglobalreg(sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); } if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) { - c &= MAPID_UPPERMASK; + job &= MAPID_UPPERMASK; sd->sktree.third = (novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) - skill_point; } } } // restore non-limiting flags - c |= sd->class_&(JOBL_UPPER|JOBL_BABY); + job |= sd->job & (JOBL_UPPER|JOBL_BABY); - return c; + return job; } /*========================================== @@ -1818,37 +1916,40 @@ int pc_updateweightstatus(struct map_session_data *sd) return 0; } -int pc_disguise(struct map_session_data *sd, int class_) { - if (class_ == -1 && sd->disguise == -1) +int pc_disguise(struct map_session_data *sd, int class) +{ + nullpo_ret(sd); + if (class == -1 && sd->disguise == -1) return 0; - if (class_ >= 0 && sd->disguise == class_) + if (class >= 0 && sd->disguise == class) return 0; if (pc_isinvisible(sd)) { //Character is invisible. Stealth class-change. [Skotlex] - sd->disguise = class_; //viewdata is set on uncloaking. + sd->disguise = class; //viewdata is set on uncloaking. return 2; } if (sd->bl.prev != NULL) { - if( class_ == -1 && sd->disguise == sd->status.class_ ) { + if (class == -1 && sd->disguise == sd->status.class) { clif->clearunit_single(-sd->bl.id,CLR_OUTSIGHT,sd->fd); - } else if ( class_ != sd->status.class_ ) { + } else if (class != sd->status.class) { pc_stop_walking(sd, STOPWALKING_FLAG_NONE); clif->clearunit_area(&sd->bl, CLR_OUTSIGHT); } } - if (class_ == -1) { + if (class == -1) { sd->disguise = -1; - class_ = sd->status.class_; - } else - sd->disguise = class_; + class = sd->status.class; + } else { + sd->disguise = class; + } - status->set_viewdata(&sd->bl, class_); + status->set_viewdata(&sd->bl, class); clif->changeoption(&sd->bl); // We need to update the client so it knows that a costume is being used if( sd->sc.option&OPTION_COSTUME ) { - clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); + clif->changelook(&sd->bl, LOOK_BASE, sd->vd.class); clif->changelook(&sd->bl,LOOK_WEAPON,0); clif->changelook(&sd->bl,LOOK_SHIELD,0); clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); @@ -1856,13 +1957,13 @@ int pc_disguise(struct map_session_data *sd, int class_) { if (sd->bl.prev != NULL) { clif->spawn(&sd->bl); - if (class_ == sd->status.class_ && pc_iscarton(sd)) { + if (class == sd->status.class && pc_iscarton(sd)) { //It seems the cart info is lost on undisguise. clif->cartlist(sd); clif->updatestatus(sd,SP_CARTINFO); } - if (sd->chatID) { - struct chat_data *cd = map->id2cd(sd->chatID); + if (sd->chat_id != 0) { + struct chat_data *cd = map->id2cd(sd->chat_id); if (cd != NULL) clif->dispchat(cd,0); @@ -1878,6 +1979,8 @@ int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, s if( !rate ) return 0; + nullpo_ret(spell); + Assert_ret(max <= 15); // autospell array size for( i = 0; i < max && spell[i].id; i++ ) { if( (spell[i].card_id == card_id || spell[i].rate < 0 || rate < 0) && spell[i].id == id && spell[i].lv == lv ) @@ -1914,6 +2017,8 @@ int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_ski if( !rate ) return 0; + nullpo_ret(spell); + Assert_ret(max <= 15); // autospell array size for( i = 0; i < max && spell[i].id; i++ ) { ; // each autospell works independently @@ -1949,6 +2054,8 @@ int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_ski int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, int16 rate, int16 arrow_rate, uint8 flag, uint16 duration) { int i; + + nullpo_ret(effect); if (!(flag&(ATF_SHORT|ATF_LONG))) flag|=ATF_SHORT|ATF_LONG; //Default range: both if (!(flag&(ATF_TARGET|ATF_SELF))) @@ -1978,6 +2085,8 @@ int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, int16 int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill_id, unsigned char target) { int i; + + nullpo_ret(effect); for( i = 0; i < max && effect[i].skill; i++ ) { if( effect[i].id == id && effect[i].skill == skill_id && effect[i].target == target ) { effect[i].rate += rate; @@ -1998,6 +2107,7 @@ int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_ int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race_mask, int rate) { int i; + nullpo_ret(drop); //Apply config rate adjustment settings. if (rate >= 0) { //Absolute drop. if (battle_config.item_rate_adddrop != 100) @@ -2045,6 +2155,8 @@ int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short int 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) { int i; + nullpo_ret(bonus); + nullpo_ret(bonus_script); ARR_FIND(0, max, i, bonus[i].rate == 0); if( i == max ) { @@ -2081,6 +2193,7 @@ int pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,c { int i; nullpo_ret(sd); + nullpo_ret(autobonus); for( i = 0; i < max; i++ ) { @@ -2152,6 +2265,7 @@ int pc_bonus_addele(struct map_session_data* sd, unsigned char ele, short rate, int i; struct weapon_data* wd; + nullpo_ret(sd); wd = (sd->state.lr_flag ? &sd->left_weapon : &sd->right_weapon); ARR_FIND(0, MAX_PC_BONUS, i, wd->addele2[i].rate == 0); @@ -2185,6 +2299,7 @@ int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate, { int i; + nullpo_ret(sd); ARR_FIND(0, MAX_PC_BONUS, i, sd->subele2[i].rate == 0); if (i == MAX_PC_BONUS) @@ -2883,6 +2998,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) { break; default: ShowWarning("pc_bonus: unknown type %d %d !\n",type,val); + Assert_report(0); break; } return 0; @@ -3675,6 +3791,7 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val) #endif default: ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); + Assert_report(0); break; } return 0; @@ -3847,6 +3964,7 @@ int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) default: ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); + Assert_report(0); break; } @@ -3941,6 +4059,7 @@ int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4 default: ShowWarning("pc_bonus4: unknown type %d %d %d %d %d!\n",type,type2,type3,type4,val); + Assert_report(0); break; } @@ -3968,6 +4087,7 @@ int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4 default: ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val); + Assert_report(0); break; } @@ -4085,7 +4205,7 @@ bool pc_can_insert_card_into(struct map_session_data* sd, int idx_card, int idx_ ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0); if (i == sd->inventory_data[idx_equip]->slot) return false; // no free slots - return true; + return true; } /** @@ -4105,7 +4225,7 @@ bool pc_can_insert_card(struct map_session_data* sd, int idx_card) return false; // target card missing if (sd->inventory_data[idx_card]->type != IT_CARD) return false; // must be a card - return true; + return true; } /*========================================== @@ -4129,7 +4249,7 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) // remember the card id to insert nameid = sd->status.inventory[idx_card].nameid; - if( pc->delitem(sd, idx_card, 1, 1, DELITEM_NORMAL, LOG_TYPE_OTHER) == 1 ) + if( pc->delitem(sd, idx_card, 1, 1, DELITEM_NORMAL, LOG_TYPE_CARD) == 1 ) {// failed clif->insert_card(sd,idx_equip,idx_card,1); } @@ -4139,9 +4259,9 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0); if (i == sd->inventory_data[idx_equip]->slot) return 0; // no free slots - logs->pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); + logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); sd->status.inventory[idx_equip].card[i] = nameid; - logs->pick_pc(sd, LOG_TYPE_OTHER, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); + logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[idx_equip],sd->inventory_data[idx_equip]); clif->insert_card(sd,idx_equip,idx_card,0); return 1; } @@ -4268,7 +4388,7 @@ int pc_payzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, if( zeny > 0 && sd->state.showzeny ) { char output[255]; sprintf(output, "Removed %dz.", zeny); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return 0; @@ -4310,7 +4430,7 @@ int pc_paycash(struct map_session_data *sd, int price, int points) { char output[128]; sprintf(output, msg_sd(sd,504), points, cash, sd->kafraPoints, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return cash+points; } @@ -4335,7 +4455,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) if( battle_config.cashshop_show_points ) { sprintf(output, msg_sd(sd,505), cash, sd->cashPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return cash; } @@ -4358,7 +4478,7 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) if( battle_config.cashshop_show_points ) { sprintf(output, msg_sd(sd,506), points, sd->kafraPoints); - clif_disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output); } return points; } @@ -4396,7 +4516,7 @@ int pc_getzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type, if( zeny > 0 && sd->state.showzeny ) { char output[255]; sprintf(output, "Gained %dz.", zeny); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return 0; @@ -4555,6 +4675,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l int pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type) { nullpo_retr(1, sd); + Assert_retr(1, n >= 0 && n < MAX_INVENTORY); if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL) return 1; @@ -4602,13 +4723,13 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) return 0; if( map->list[sd->bl.m].flag.nodrop ) { - clif->message (sd->fd, msg_sd(sd,271)); - return 0; //Can't drop items in nodrop mapflag maps. + clif->message (sd->fd, msg_sd(sd,271)); // You can't drop items in this map + return 0; } if( !pc->candrop(sd,&sd->status.inventory[n]) ) { - clif->message (sd->fd, msg_sd(sd,263)); + clif->message (sd->fd, msg_sd(sd,263)); // This item cannot be dropped. return 0; } @@ -4698,6 +4819,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) int nameid; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); item = sd->inventory_data[n]; nameid = sd->status.inventory[n].nameid; @@ -4723,17 +4845,43 @@ int pc_isUseitem(struct map_session_data *sd,int n) switch( nameid ) { // TODO: Is there no better way to handle this, other than hardcoding item IDs? case ITEMID_ANODYNE: - if( map_flag_gvg2(sd->bl.m) ) - return 0; - /* Fall through */ - case ITEMID_ALOEBERA: - if( pc_issit(sd) ) + if (map_flag_gvg2(sd->bl.m)) return 0; break; + + case ITEMID_GIANT_FLY_WING: { + struct party_data *p; + + if (!sd->status.party_id) { + clif->msgtable(sd, MSG_PARTY_MEMBER_NOT_SUMMONED); + break; + } + + if ((p = party->search(sd->status.party_id)) != NULL) { + int i; + int16 m; + + ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd); + + if (i == MAX_PARTY || !p->party.member[i].leader) { + clif->msgtable(sd, MSG_PARTY_MEMBER_NOT_SUMMONED); + break; + } + + m = sd->bl.m; + + ARR_FIND(0, MAX_PARTY, i, p->data[i].sd && p->data[i].sd != sd && p->data[i].sd->bl.m == m); + + if (i == MAX_PARTY || pc_isdead(p->data[i].sd)) { + clif->msgtable(sd, MSG_PARTY_NO_MEMBER_IN_MAP); + break; + } + } + } + FALLTHROUGH case ITEMID_WING_OF_FLY: - case ITEMID_GIANT_FLY_WING: - if( map->list[sd->bl.m].flag.noteleport || map_flag_gvg2(sd->bl.m) ) { - clif->skill_mapinfomessage(sd,0); + if (map->list[sd->bl.m].flag.noteleport || map_flag_gvg2(sd->bl.m)) { + clif->skill_mapinfomessage(sd, 0); return 0; } /* Fall through */ @@ -4759,25 +4907,6 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m) ) return 0; break; - case ITEMID_BUBBLE_GUM: - case ITEMID_COMP_BUBBLE_GUM: - if( sd->sc.data[SC_CASH_RECEIVEITEM] ) - return 0; - break; - case ITEMID_BATTLE_MANUAL: - case ITEMID_COMP_BATTLE_MANUAL: - case ITEMID_THICK_MANUAL50: - case ITEMID_NOBLE_NAMEPLATE: - case ITEMID_BATTLE_MANUAL25: - case ITEMID_BATTLE_MANUAL100: - case ITEMID_BATTLE_MANUAL_X3: - if( sd->sc.data[SC_CASH_PLUSEXP] ) - return 0; - break; - case ITEMID_JOB_MANUAL50: - if( sd->sc.data[SC_CASH_PLUSONLYJOBEXP] ) - return 0; - break; // Mercenary Items case ITEMID_MERCENARY_RED_POTION: @@ -4804,17 +4933,6 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( nameid >= ITEMID_BOW_MERCENARY_SCROLL1 && nameid <= ITEMID_SPEARMERCENARY_SCROLL10 && sd->md != NULL ) // Mercenary Scrolls return 0; - /** - * Only Rune Knights may use runes - **/ - if( itemdb_is_rune(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT ) - return 0; - /** - * Only GCross may use poisons - **/ - else if( itemdb_is_poison(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_GUILLOTINE_CROSS ) - return 0; - if( item->package || item->group ) { if (pc_is90overweight(sd)) { clif->msgtable(sd, MSG_ITEM_CANT_OBTAIN_WEIGHT); @@ -4830,42 +4948,58 @@ int pc_isUseitem(struct map_session_data *sd,int n) if(item->sex != 2 && sd->status.sex != item->sex) return 0; //Required level check - if (item->elv && sd->status.base_level < (unsigned int)item->elv) { + if (item->elv && sd->status.base_level < item->elv) { clif->msgtable(sd, MSG_ITEM_CANT_USE_LVL); return 0; } - if (item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) { + if (item->elvmax && sd->status.base_level > item->elvmax) { clif->msgtable(sd, MSG_ITEM_CANT_USE_LVL); return 0; } //Not equipable by class. [Skotlex] - if (!( - (1<<(sd->class_&MAPID_BASEMASK)) & - (item->class_base[(sd->class_&JOBL_2_1) ? 1 : ((sd->class_&JOBL_2_2) ? 2 : 0)]) - )) + if (((1ULL << (sd->job & MAPID_BASEMASK)) & (item->class_base[(sd->job & JOBL_2_1) ? 1 : ((sd->job & JOBL_2_2) ? 2 : 0)])) == 0) return 0; //Not usable by upper class. [Haru] while( 1 ) { // Normal classes (no upper, no baby, no third classes) - if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; + if ((item->class_upper & ITEMUPPER_NORMAL) != 0) { + if ((sd->job & (JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) == 0) + break; + } + if ((item->class_upper & ITEMUPPER_UPPER) != 0) { #ifdef RENEWAL - // Upper classes (no third classes) - if( item->class_upper&ITEMUPPER_UPPER && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) break; + // Upper classes (no third classes) + if ((sd->job & JOBL_UPPER) != 0 && (sd->job&JOBL_THIRD) == 0) + break; #else - //pre-re has no use for the extra, so we maintain the previous for backwards compatibility - if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; + //pre-re has no use for the extra, so we maintain the previous for backwards compatibility + if ((sd->job & (JOBL_UPPER|JOBL_THIRD)) != 0) + break; #endif + } // Baby classes (no third classes) - if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) break; + if ((item->class_upper & ITEMUPPER_BABY) != 0) { + if ((sd->job & JOBL_BABY) != 0 && (sd->job&JOBL_THIRD) == 0) + break; + } // Third classes (no upper, no baby classes) - if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) ) break; + if ((item->class_upper & ITEMUPPER_THIRD) != 0) { + if ((sd->job & JOBL_THIRD) != 0 && (sd->job & (JOBL_UPPER|JOBL_BABY)) == 0) + break; + } // Upper third classes - if( item->class_upper&ITEMUPPER_THURDUPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break; + if ((item->class_upper & ITEMUPPER_THURDUPPER) != 0) { + if ((sd->job & JOBL_THIRD) != 0 && (sd->job & JOBL_UPPER) != 0) + break; + } // Baby third classes - if( item->class_upper&ITEMUPPER_THIRDBABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break; + if ((item->class_upper & ITEMUPPER_THIRDBABY) != 0) { + if ((sd->job & JOBL_THIRD) != 0 && (sd->job & JOBL_BABY) != 0) + break; + } return 0; } @@ -4884,11 +5018,13 @@ int pc_useitem(struct map_session_data *sd,int n) { bool removeItem = false; nullpo_ret(sd); + Assert_ret(n >= 0 && n < MAX_INVENTORY); - if( sd->npc_id || sd->state.workinprogress&1 ){ - /* TODO: add to clif->messages enum */ -#ifdef RENEWAL - clif->msgtable(sd, MSG_NPC_WORK_IN_PROGRESS); // TODO look for the client date that has this message. + if (sd->npc_id || sd->state.workinprogress & 1) { +#if PACKETVER >= 20110309 + clif->msgtable(sd, MSG_NPC_WORK_IN_PROGRESS); +#else + clif->messagecolor_self(sd->fd, COLOR_WHITE, msg_sd(sd, 48)); #endif return 0; } @@ -4919,18 +5055,17 @@ int pc_useitem(struct map_session_data *sd,int n) { sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC_COLD] || + sd->sc.data[SC_SUHIDE] || pc_ismuted(&sd->sc, MANNER_NOITEM) )) return 0; - //Prevent mass item usage. [Skotlex] - if( DIFF_TICK(sd->canuseitem_tick, tick) > 0 || - (itemdb_iscashfood(nameid) && DIFF_TICK(sd->canusecashfood_tick, tick) > 0) - ) + // Prevent mass item usage. [Skotlex] + if (DIFF_TICK(sd->canuseitem_tick, tick) > 0) return 0; /* Items with delayed consume are not meant to work while in mounts except reins of mount(12622) */ - if( sd->inventory_data[n]->flag.delay_consume && nameid != ITEMID_REINS_OF_MOUNT ) { + if (sd->inventory_data[n]->flag.delay_consume && nameid != ITEMID_BOARDING_HALTER) { if( sd->sc.data[SC_ALL_RIDING] ) return 0; else if( pc_issit(sd) ) @@ -4943,21 +5078,28 @@ int pc_useitem(struct map_session_data *sd,int n) { if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status->check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) ) return 0; - if( sd->inventory_data[n]->delay > 0 ) { - ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid ); - if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */ - ARR_FIND(0, MAX_ITEMDELAYS, i, !sd->item_delay[i].nameid ); - if( i < MAX_ITEMDELAYS ) { - if( sd->item_delay[i].nameid ) {// found - if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) { - int e_tick = (int)(DIFF_TICK(sd->item_delay[i].tick, tick)/1000); - clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, e_tick + 1); // [%d] seconds left until you can use + if (sd->inventory_data[n]->delay > 0) { + ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid); + if (i == MAX_ITEMDELAYS) /* item not found. try first empty now */ + ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == 0); + if (i < MAX_ITEMDELAYS) { + if (sd->item_delay[i].nameid != 0) {// found + if (DIFF_TICK(sd->item_delay[i].tick, tick) > 0) { + int delay_tick = (int)(DIFF_TICK(sd->item_delay[i].tick, tick) / 1000); +#if PACKETVER >= 20101123 + clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use +#else + char delay_msg[100]; + clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use + sprintf(delay_msg, msg_sd(sd, 26), delay_tick + 1); + clif->messagecolor_self(sd->fd, COLOR_YELLOW, delay_msg); +#endif return 0; // Delay has not expired yet } } else {// not yet used item (all slots are initially empty) sd->item_delay[i].nameid = nameid; } - if (!(nameid == ITEMID_REINS_OF_MOUNT && pc_hasmount(sd))) + if (!(nameid == ITEMID_BOARDING_HALTER && pc_hasmount(sd))) sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay; } else {// should not happen ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%d, char_id=%d)\n", nameid, sd->status.char_id); @@ -5005,18 +5147,15 @@ int pc_useitem(struct map_session_data *sd,int n) { } } - if(sd->status.inventory[n].card[0]==CARD0_CREATE && - pc->famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST)) - { + if (sd->status.inventory[n].card[0] == CARD0_CREATE + && pc->fame_rank(MakeDWord(sd->status.inventory[n].card[2], sd->status.inventory[n].card[3]), RANKTYPE_ALCHEMIST) > 0) { script->potion_flag = 2; // Famous player's potions have 50% more efficiency if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ROGUE) script->potion_flag = 3; //Even more effective potions. } - //Update item use time. + // Update item use time. sd->canuseitem_tick = tick + battle_config.item_use_interval; - if( itemdb_iscashfood(nameid) ) - sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval; script->run_use_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id); script->potion_flag = 0; @@ -5051,7 +5190,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun if (!itemdb_cancartstore(item_data, pc_get_group_level(sd)) || (item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd))) { // Check item trade restrictions - clif->message (sd->fd, msg_sd(sd,264)); + clif->message (sd->fd, msg_sd(sd,264)); // This item cannot be stored. return 1;/* TODO: there is no official response to this? */ } @@ -5104,6 +5243,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_pick_type log_type) { struct item_data * data; nullpo_retr(1, sd); + Assert_retr(1, n >= 0 && n < MAX_INVENTORY); if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb->exists(sd->status.cart[n].nameid)) ) return 1; @@ -5162,6 +5302,7 @@ int pc_cartitem_amount(struct map_session_data* sd, int idx, int amount) struct item* item_data; nullpo_retr(-1, sd); + Assert_retr(-1, idx >= 0 && idx < MAX_CART); item_data = &sd->status.cart[idx]; if( item_data->nameid == 0 || item_data->amount == 0 ) @@ -5196,9 +5337,12 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) return flag; } -void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) { + +void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) +{ int i; + nullpo_retv(sd); switch( type ) { /* both restricted to inventory */ case IBT_PARTY: @@ -5328,26 +5472,21 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil //Logs items, Stolen from mobs [Lupus] logs->pick_mob(md, LOG_TYPE_STEAL, -1, &tmp_item, data); - //A Rare Steal Global Announce by Lupus - if(md->db->dropitem[i].p<=battle_config.rare_drop_announce) { - char message[128]; - sprintf (message, msg_txt(542), sd->status.name, md->db->jname, data->jname, (float)md->db->dropitem[i].p / 100); - //MSG: "'%s' stole %s's %s (chance: %0.02f%%)" - intif->broadcast(message, strlen(message)+1, BC_DEFAULT); - } return 1; } /** * Steals zeny from a monster through the RG_STEALCOIN skill. * - * @param sd Source character - * @param target Target monster + * @param sd Source character + * @param target Target monster + * @param skill_lv Skill Level * * @return Amount of stolen zeny (0 in case of failure) - **/ -int pc_steal_coin(struct map_session_data *sd, struct block_list *target) { - int rate, skill_lv; + */ +int pc_steal_coin(struct map_session_data *sd, struct block_list *target, uint16 skill_lv) +{ + int rate; struct mob_data *md = BL_CAST(BL_MOB, target); if (sd == NULL || md == NULL) @@ -5359,7 +5498,6 @@ int pc_steal_coin(struct map_session_data *sd, struct block_list *target) { if (mob_is_treasure(md)) return 0; - skill_lv = pc->checkskill(sd, RG_STEALCOIN); rate = skill_lv * 10 + (sd->status.base_level - md->level) * 2 + sd->battle_status.dex / 2 + sd->battle_status.luk / 2; if(rnd()%1000 < rate) { 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] @@ -5526,6 +5664,8 @@ int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int npc->script_event(sd, NPCE_LOGOUT); //remove from map, THEN change x/y coordinates unit->remove_map_pc(sd,clrtype); + if (battle_config.player_warp_keep_direction == 0) + sd->ud.dir = 0; // makes character face north sd->mapindex = map_index; sd->bl.x=x; sd->bl.y=y; @@ -5556,6 +5696,9 @@ int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int vending->close(sd); } + if (battle_config.player_warp_keep_direction == 0) + sd->ud.dir = 0; // makes character face north + if(sd->bl.prev != NULL){ unit->remove_map_pc(sd,clrtype); clif->changemap(sd,m,x,y); // [MouseJstr] @@ -5805,10 +5948,9 @@ int pc_checkequip(struct map_session_data *sd,int pos) * Convert's from the client's lame Job ID system * to the map server's 'makes sense' system. [Skotlex] *------------------------------------------*/ -int pc_jobid2mapid(unsigned short b_class) +int pc_jobid2mapid(int16 class) { - switch(b_class) - { + switch (class) { //Novice And 1-1 Jobs case JOB_NOVICE: return MAPID_NOVICE; case JOB_SWORDMAN: return MAPID_SWORDMAN; @@ -5824,6 +5966,7 @@ int pc_jobid2mapid(unsigned short b_class) case JOB_XMAS: return MAPID_XMAS; case JOB_SUMMER: return MAPID_SUMMER; case JOB_GANGSI: return MAPID_GANGSI; + case JOB_SUMMONER: return MAPID_SUMMONER; //2-1 Jobs case JOB_SUPER_NOVICE: return MAPID_SUPER_NOVICE; case JOB_KNIGHT: return MAPID_KNIGHT; @@ -5947,10 +6090,9 @@ int pc_jobid2mapid(unsigned short b_class) } //Reverts the map-style class id to the client-style one. -int pc_mapid2jobid(unsigned short class_, int sex) +int pc_mapid2jobid(uint16 job, int sex) { - switch(class_) - { + switch (job) { //Novice And 1-1 Jobs case MAPID_NOVICE: return JOB_NOVICE; case MAPID_SWORDMAN: return JOB_SWORDMAN; @@ -5966,6 +6108,7 @@ int pc_mapid2jobid(unsigned short class_, int sex) case MAPID_XMAS: return JOB_XMAS; case MAPID_SUMMER: return JOB_SUMMER; case MAPID_GANGSI: return JOB_GANGSI; + case MAPID_SUMMONER: return JOB_SUMMONER; //2-1 Jobs case MAPID_SUPER_NOVICE: return JOB_SUPER_NOVICE; case MAPID_KNIGHT: return JOB_KNIGHT; @@ -6084,9 +6227,9 @@ int pc_mapid2jobid(unsigned short class_, int sex) /*==================================================== * This function return the name of the job (by [Yor]) *----------------------------------------------------*/ -const char* job_name(int class_) +const char *job_name(int class) { - switch (class_) { + switch (class) { case JOB_NOVICE: // 550 case JOB_SWORDMAN: // 551 case JOB_MAGE: // 552 @@ -6094,7 +6237,7 @@ const char* job_name(int class_) case JOB_ACOLYTE: // 554 case JOB_MERCHANT: // 555 case JOB_THIEF: // 556 - return msg_txt(550 - JOB_NOVICE+class_); + return msg_txt(550 - JOB_NOVICE + class); case JOB_KNIGHT: // 557 case JOB_PRIEST: // 558 @@ -6102,7 +6245,7 @@ const char* job_name(int class_) case JOB_BLACKSMITH: // 560 case JOB_HUNTER: // 561 case JOB_ASSASSIN: // 562 - return msg_txt(557 - JOB_KNIGHT+class_); + return msg_txt(557 - JOB_KNIGHT + class); case JOB_KNIGHT2: return msg_txt(557); @@ -6114,7 +6257,7 @@ const char* job_name(int class_) case JOB_ALCHEMIST: // 567 case JOB_BARD: // 568 case JOB_DANCER: // 569 - return msg_txt(563 - JOB_CRUSADER+class_); + return msg_txt(563 - JOB_CRUSADER + class); case JOB_CRUSADER2: return msg_txt(563); @@ -6124,7 +6267,7 @@ const char* job_name(int class_) case JOB_GUNSLINGER: // 572 case JOB_NINJA: // 573 case JOB_XMAS: // 574 - return msg_txt(570 - JOB_WEDDING+class_); + return msg_txt(570 - JOB_WEDDING + class); case JOB_SUMMER: return msg_txt(621); @@ -6136,7 +6279,7 @@ const char* job_name(int class_) case JOB_ACOLYTE_HIGH: // 579 case JOB_MERCHANT_HIGH: // 580 case JOB_THIEF_HIGH: // 581 - return msg_txt(575 - JOB_NOVICE_HIGH+class_); + return msg_txt(575 - JOB_NOVICE_HIGH + class); case JOB_LORD_KNIGHT: // 582 case JOB_HIGH_PRIEST: // 583 @@ -6144,7 +6287,7 @@ const char* job_name(int class_) case JOB_WHITESMITH: // 585 case JOB_SNIPER: // 586 case JOB_ASSASSIN_CROSS: // 587 - return msg_txt(582 - JOB_LORD_KNIGHT+class_); + return msg_txt(582 - JOB_LORD_KNIGHT + class); case JOB_LORD_KNIGHT2: return msg_txt(582); @@ -6156,7 +6299,7 @@ const char* job_name(int class_) case JOB_CREATOR: // 592 case JOB_CLOWN: // 593 case JOB_GYPSY: // 594 - return msg_txt(588 - JOB_PALADIN + class_); + return msg_txt(588 - JOB_PALADIN + class); case JOB_PALADIN2: return msg_txt(588); @@ -6168,7 +6311,7 @@ const char* job_name(int class_) case JOB_BABY_ACOLYTE: // 599 case JOB_BABY_MERCHANT: // 600 case JOB_BABY_THIEF: // 601 - return msg_txt(595 - JOB_BABY + class_); + return msg_txt(595 - JOB_BABY + class); case JOB_BABY_KNIGHT: // 602 case JOB_BABY_PRIEST: // 603 @@ -6176,7 +6319,7 @@ const char* job_name(int class_) case JOB_BABY_BLACKSMITH: // 605 case JOB_BABY_HUNTER: // 606 case JOB_BABY_ASSASSIN: // 607 - return msg_txt(602 - JOB_BABY_KNIGHT + class_); + return msg_txt(602 - JOB_BABY_KNIGHT + class); case JOB_BABY_KNIGHT2: return msg_txt(602); @@ -6188,7 +6331,7 @@ const char* job_name(int class_) case JOB_BABY_ALCHEMIST: // 612 case JOB_BABY_BARD: // 613 case JOB_BABY_DANCER: // 614 - return msg_txt(608 - JOB_BABY_CRUSADER + class_); + return msg_txt(608 - JOB_BABY_CRUSADER + class); case JOB_BABY_CRUSADER2: return msg_txt(608); @@ -6207,7 +6350,7 @@ const char* job_name(int class_) case JOB_GANGSI: // 622 case JOB_DEATH_KNIGHT: // 623 case JOB_DARK_COLLECTOR: // 624 - return msg_txt(622 - JOB_GANGSI+class_); + return msg_txt(622 - JOB_GANGSI + class); case JOB_RUNE_KNIGHT: // 625 case JOB_WARLOCK: // 626 @@ -6215,7 +6358,7 @@ const char* job_name(int class_) case JOB_ARCH_BISHOP: // 628 case JOB_MECHANIC: // 629 case JOB_GUILLOTINE_CROSS: // 630 - return msg_txt(625 - JOB_RUNE_KNIGHT+class_); + return msg_txt(625 - JOB_RUNE_KNIGHT + class); case JOB_RUNE_KNIGHT_T: // 656 case JOB_WARLOCK_T: // 657 @@ -6223,7 +6366,7 @@ const char* job_name(int class_) case JOB_ARCH_BISHOP_T: // 659 case JOB_MECHANIC_T: // 660 case JOB_GUILLOTINE_CROSS_T: // 661 - return msg_txt(656 - JOB_RUNE_KNIGHT_T+class_); + return msg_txt(656 - JOB_RUNE_KNIGHT_T + class); case JOB_ROYAL_GUARD: // 631 case JOB_SORCERER: // 632 @@ -6232,7 +6375,7 @@ const char* job_name(int class_) case JOB_SURA: // 635 case JOB_GENETIC: // 636 case JOB_SHADOW_CHASER: // 637 - return msg_txt(631 - JOB_ROYAL_GUARD+class_); + return msg_txt(631 - JOB_ROYAL_GUARD + class); case JOB_ROYAL_GUARD_T: // 662 case JOB_SORCERER_T: // 663 @@ -6241,7 +6384,7 @@ const char* job_name(int class_) case JOB_SURA_T: // 666 case JOB_GENETIC_T: // 667 case JOB_SHADOW_CHASER_T: // 668 - return msg_txt(662 - JOB_ROYAL_GUARD_T+class_); + return msg_txt(662 - JOB_ROYAL_GUARD_T + class); case JOB_RUNE_KNIGHT2: return msg_txt(625); @@ -6280,7 +6423,7 @@ const char* job_name(int class_) case JOB_BABY_SURA: // 648 case JOB_BABY_GENETIC: // 649 case JOB_BABY_CHASER: // 650 - return msg_txt(638 - JOB_BABY_RUNE+class_); + return msg_txt(638 - JOB_BABY_RUNE + class); case JOB_BABY_RUNE2: return msg_txt(638); @@ -6296,15 +6439,18 @@ const char* job_name(int class_) case JOB_SUPER_NOVICE_E: // 651 case JOB_SUPER_BABY_E: // 652 - return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); + return msg_txt(651 - JOB_SUPER_NOVICE_E + class); case JOB_KAGEROU: // 653 case JOB_OBORO: // 654 - return msg_txt(653 - JOB_KAGEROU+class_); + return msg_txt(653 - JOB_KAGEROU + class); case JOB_REBELLION: return msg_txt(655); + case JOB_SUMMONER: + return msg_txt(669); + default: return msg_txt(620); // "Unknown Job" } @@ -6430,8 +6576,10 @@ int pc_check_job_name(const char *name) { { "Kagerou", JOB_KAGEROU }, { "Oboro", JOB_OBORO }, { "Rebellion", JOB_REBELLION }, + { "Summoner", JOB_SUMMONER }, }; + nullpo_retr(-1, name); len = ARRAYLENGTH(names); ARR_FIND(0, len, i, strcmpi(names[i].name, name) == 0); @@ -6498,6 +6646,7 @@ int pc_stop_following (struct map_session_data *sd) int pc_follow(struct map_session_data *sd,int target_id) { struct block_list *bl = map->id2bl(target_id); + nullpo_retr(1, sd); if (bl == NULL /*|| bl->type != BL_PC*/) return 1; if (sd->followtimer != INVALID_TIMER) @@ -6512,18 +6661,20 @@ int pc_follow(struct map_session_data *sd,int target_id) { int pc_checkbaselevelup(struct map_session_data *sd) { unsigned int next = pc->nextbaseexp(sd); + nullpo_ret(sd); if (!next || sd->status.base_exp < next) return 0; do { + int status_points = 0; sd->status.base_exp -= next; //Kyoki pointed out that the max overcarry exp is the exp needed for the previous level -1. [Skotlex] if(!battle_config.multi_level_up && sd->status.base_exp > next-1) sd->status.base_exp = next-1; - next = pc->gets_status_point(sd->status.base_level); - sd->status.base_level ++; - sd->status.status_point += next; + status_points = pc->gets_status_point(sd->status.base_level); + sd->status.base_level++; + sd->status.status_point += status_points; } while ((next=pc->nextbaseexp(sd)) > 0 && sd->status.base_exp >= next); @@ -6537,7 +6688,7 @@ int pc_checkbaselevelup(struct map_session_data *sd) { status_calc_pc(sd,SCO_FORCE); status_percent_heal(&sd->bl,100,100); - if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) { + if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) { sc_start(NULL,&sd->bl,status->skill2sc(PR_KYRIE),100,1,skill->get_time(PR_KYRIE,1)); sc_start(NULL,&sd->bl,status->skill2sc(PR_IMPOSITIO),100,1,skill->get_time(PR_IMPOSITIO,1)); sc_start(NULL,&sd->bl,status->skill2sc(PR_MAGNIFICAT),100,1,skill->get_time(PR_MAGNIFICAT,1)); @@ -6545,7 +6696,7 @@ int pc_checkbaselevelup(struct map_session_data *sd) { sc_start(NULL,&sd->bl,status->skill2sc(PR_SUFFRAGIUM),100,1,skill->get_time(PR_SUFFRAGIUM,1)); if (sd->state.snovice_dead_flag) sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead. - } else if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) { + } else if ((sd->job & MAPID_BASEMASK) == MAPID_TAEKWON) { sc_start(NULL,&sd->bl,status->skill2sc(AL_INCAGI),100,10,600000); sc_start(NULL,&sd->bl,status->skill2sc(AL_BLESSING),100,10,600000); } @@ -6561,9 +6712,10 @@ int pc_checkbaselevelup(struct map_session_data *sd) { void pc_baselevelchanged(struct map_session_data *sd) { int i; + nullpo_retv(sd); for( i = 0; i < EQI_MAX; i++ ) { if( sd->equip_index[i] >= 0 ) { - if( sd->inventory_data[ sd->equip_index[i] ]->elvmax && sd->status.base_level > (unsigned int)sd->inventory_data[ sd->equip_index[i] ]->elvmax ) + if (sd->inventory_data[sd->equip_index[i]]->elvmax != 0 && sd->status.base_level > sd->inventory_data[ sd->equip_index[i] ]->elvmax) pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); } } @@ -6583,8 +6735,8 @@ int pc_checkjoblevelup(struct map_session_data *sd) if(!battle_config.multi_level_up && sd->status.job_exp > next-1) sd->status.job_exp = next-1; - sd->status.job_level ++; - sd->status.skill_point ++; + sd->status.job_level++; + sd->status.skill_point++; } while ((next=pc->nextjobexp(sd)) > 0 && sd->status.job_exp >= next); @@ -6605,34 +6757,72 @@ int pc_checkjoblevelup(struct map_session_data *sd) * Alters EXP based on self bonuses that do not get shared with the party **/ void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src) { - int bonus = 0; - struct status_data *st = status->get_status_data(src); + int buff_ratio = 0, buff_job_ratio = 0, race_ratio = 0, pk_ratio = 0; + int64 jexp, bexp; - if (sd->expaddrace[st->race]) - bonus += sd->expaddrace[st->race]; - bonus += sd->expaddrace[(st->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS]; + nullpo_retv(sd); + nullpo_retv(base_exp); + nullpo_retv(job_exp); + + jexp = *job_exp; + bexp = *base_exp; + + if (src != NULL) { + const struct status_data *st = status->get_status_data(src); + +#ifdef RENEWAL_EXP //should happen first before we caluclate any modifiers + if (src->type == BL_MOB) { + const struct mob_data *md = BL_UCAST(BL_MOB, src); + int re_mod; + re_mod = pc->level_penalty_mod(md->level - sd->status.base_level, md->status.race, md->status.mode, 1); + jexp = apply_percentrate64(jexp, re_mod, 100); + bexp = apply_percentrate64(bexp, re_mod, 100); + } +#endif - if (battle_config.pk_mode - && (int)(status->get_lv(src) - sd->status.base_level) >= 20) - bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris] + //Race modifier + if (sd->expaddrace[st->race]) + race_ratio += sd->expaddrace[st->race]; + race_ratio += sd->expaddrace[(st->mode&MD_BOSS) ? RC_BOSS : RC_NONBOSS]; + } - if (sd->sc.data[SC_CASH_PLUSEXP]) - bonus += sd->sc.data[SC_CASH_PLUSEXP]->val1; - if (sd->sc.data[SC_OVERLAPEXPUP]) - bonus += sd->sc.data[SC_OVERLAPEXPUP]->val1; - *base_exp = (unsigned int) cap_value(*base_exp + apply_percentrate64(*base_exp, bonus, 100), 1, UINT_MAX); + //PK modifier + /* this doesn't exist in Aegis, instead there's a CrazyKiller check which double all EXP from this point */ + if (battle_config.pk_mode && status->get_lv(src) - sd->status.base_level >= 20) + pk_ratio += 15; // pk_mode additional exp if monster >20 levels [Valaris] + + //Buffs modifier + if (sd->sc.data[SC_CASH_PLUSEXP]) { + buff_job_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1; + buff_ratio += sd->sc.data[SC_CASH_PLUSEXP]->val1; + } + if (sd->sc.data[SC_OVERLAPEXPUP]) { + buff_job_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1; + buff_ratio += sd->sc.data[SC_OVERLAPEXPUP]->val1; + } if (sd->sc.data[SC_CASH_PLUSONLYJOBEXP]) - bonus += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1; + buff_job_ratio += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1; - *job_exp = (unsigned int) cap_value(*job_exp + apply_percentrate64(*job_exp, bonus, 100), 1, UINT_MAX); + //Applying Race and PK modifier First then Premium (Perment modifier) and finally buff modifier + jexp += apply_percentrate64(jexp, race_ratio, 100); + jexp += apply_percentrate64(jexp, pk_ratio, 100); + + bexp += apply_percentrate64(bexp, race_ratio, 100); + bexp += apply_percentrate64(bexp, pk_ratio, 100); - if (sd->status.mod_exp != 100) { - *base_exp = (unsigned int) cap_value(apply_percentrate64(*base_exp, sd->status.mod_exp, 100), 1, UINT_MAX); - *job_exp = (unsigned int) cap_value(apply_percentrate64(*job_exp, sd->status.mod_exp, 100), 1, UINT_MAX); + if (sd->status.mod_exp != 100) { + jexp = apply_percentrate64(jexp, sd->status.mod_exp, 100); + bexp = apply_percentrate64(bexp, sd->status.mod_exp, 100); } + + bexp += apply_percentrate64(bexp, buff_ratio, 100); + jexp += apply_percentrate64(jexp, buff_ratio + buff_job_ratio, 100); + + *job_exp = (unsigned int)cap_value(jexp, 1, UINT_MAX); + *base_exp = (unsigned int)cap_value(bexp, 1, UINT_MAX); } /** @@ -6646,24 +6836,25 @@ bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned in unsigned int nextb=0, nextj=0; nullpo_ret(sd); - if(sd->bl.prev == NULL || pc_isdead(sd)) + if (sd->bl.prev == NULL || pc_isdead(sd)) return false; - if(!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] + if (!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] return false; // no exp on pvp maps - if( pc_has_permission(sd,PC_PERM_DISABLE_EXP) ) + if (pc_has_permission(sd,PC_PERM_DISABLE_EXP)) return false; - if(sd->status.guild_id>0) - base_exp-=guild->payexp(sd,base_exp); + if (src) + pc->calcexp(sd, &base_exp, &job_exp, src); - if(src) pc->calcexp(sd, &base_exp, &job_exp, src); + if (sd->status.guild_id > 0) + base_exp -= guild->payexp(sd,base_exp); nextb = pc->nextbaseexp(sd); nextj = pc->nextjobexp(sd); - if(sd->state.showexp || battle_config.max_exp_gain_rate){ + if (sd->state.showexp || battle_config.max_exp_gain_rate) { if (nextb > 0) nextbp = (float) base_exp / (float) nextb; if (nextj > 0) @@ -6718,7 +6909,7 @@ bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned in char output[256]; sprintf(output, "Experience Gained Base:%u (%.2f%%) Job:%u (%.2f%%)",base_exp,nextbp*(float)100,job_exp,nextjp*(float)100); - clif_disp_onlyself(sd,output,strlen(output)); + clif_disp_onlyself(sd, output); } return true; @@ -6727,14 +6918,14 @@ bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned in /*========================================== * Returns max level for this character. *------------------------------------------*/ -unsigned int pc_maxbaselv(struct map_session_data *sd) +int pc_maxbaselv(const struct map_session_data *sd) { - return pc->max_level[pc->class2idx(sd->status.class_)][0]; + return pc->max_level[pc->class2idx(sd->status.class)][0]; } -unsigned int pc_maxjoblv(struct map_session_data *sd) +int pc_maxjoblv(const struct map_session_data *sd) { - return pc->max_level[pc->class2idx(sd->status.class_)][1]; + return pc->max_level[pc->class2idx(sd->status.class)][1]; } /*========================================== @@ -6742,23 +6933,23 @@ unsigned int pc_maxjoblv(struct map_session_data *sd) *------------------------------------------*/ //Base exp needed for next level. -unsigned int pc_nextbaseexp(struct map_session_data *sd) +unsigned int pc_nextbaseexp(const struct map_session_data *sd) { nullpo_ret(sd); - if(sd->status.base_level>=pc->maxbaselv(sd) || sd->status.base_level<=0) + if (sd->status.base_level >= pc->maxbaselv(sd) || sd->status.base_level <= 0) return 0; - return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-1]; + return pc->exp_table[pc->class2idx(sd->status.class)][0][sd->status.base_level-1]; } //Base exp needed for this level. -unsigned int pc_thisbaseexp(struct map_session_data *sd) +unsigned int pc_thisbaseexp(const struct map_session_data *sd) { - if(sd->status.base_level>pc->maxbaselv(sd) || sd->status.base_level<=1) + if (sd->status.base_level > pc->maxbaselv(sd) || sd->status.base_level <= 1) return 0; - return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-2]; + return pc->exp_table[pc->class2idx(sd->status.class)][0][sd->status.base_level-2]; } /*========================================== @@ -6769,21 +6960,21 @@ unsigned int pc_thisbaseexp(struct map_session_data *sd) *------------------------------------------*/ //Job exp needed for next level. -unsigned int pc_nextjobexp(struct map_session_data *sd) +unsigned int pc_nextjobexp(const struct map_session_data *sd) { nullpo_ret(sd); - if(sd->status.job_level>=pc->maxjoblv(sd) || sd->status.job_level<=0) + if (sd->status.job_level >= pc->maxjoblv(sd) || sd->status.job_level <= 0) return 0; - return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-1]; + return pc->exp_table[pc->class2idx(sd->status.class)][1][sd->status.job_level-1]; } //Job exp needed for this level. -unsigned int pc_thisjobexp(struct map_session_data *sd) +unsigned int pc_thisjobexp(const struct map_session_data *sd) { - if(sd->status.job_level>pc->maxjoblv(sd) || sd->status.job_level<=1) + if (sd->status.job_level > pc->maxjoblv(sd) || sd->status.job_level <= 1) return 0; - return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-2]; + return pc->exp_table[pc->class2idx(sd->status.class)][1][sd->status.job_level-2]; } /// Returns the value of the specified stat. @@ -7014,13 +7205,14 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { if( sd->status.skill_point > 0 && sd->status.skill[index].id && sd->status.skill[index].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] - sd->status.skill[index].lv < skill->tree_get_max(skill_id, sd->status.class_) ) + sd->status.skill[index].lv < skill->tree_get_max(skill_id, sd->status.class) ) { sd->status.skill[index].lv++; sd->status.skill_point--; if( !skill->dbs->db[index].inf ) status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills. - 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) ) + else if (sd->status.skill_point == 0 && (sd->job & MAPID_UPPERMASK) == MAPID_TAEKWON + && sd->status.base_level >= 90 && pc->fame_rank(sd->status.char_id, RANKTYPE_TAEKWON) > 0) pc->calc_skilltree(sd); // Required to grant all TK Ranger skills. else pc->check_skilltree(sd, skill_id); // Check if a new skill can Lvlup @@ -7032,9 +7224,9 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown clif->skillinfoblock(sd); } else if( battle_config.skillup_limit ){ - if (sd->sktree.second) + if (sd->sktree.second != 0) clif->msgtable_num(sd, MSG_SKILL_POINTS_LEFT_JOB1, sd->sktree.second); - else if (sd->sktree.third) + else if (sd->sktree.third != 0) clif->msgtable_num(sd, MSG_SKILL_POINTS_LEFT_JOB2, sd->sktree.third); else if (pc->calc_skillpoint(sd) < 9) /* TODO: official response? */ clif->messagecolor_self(sd->fd, COLOR_RED, "You need the basic skills"); @@ -7076,8 +7268,8 @@ int pc_allskillup(struct map_session_data *sd) } } else { int id; - for (i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[pc->class2idx(sd->status.class_)][i].id) > 0; i++) { - int idx = pc->skill_tree[pc->class2idx(sd->status.class_)][i].idx; + for (i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[pc->class2idx(sd->status.class)][i].id) > 0; i++) { + int idx = pc->skill_tree[pc->class2idx(sd->status.class)][i].idx; int inf2 = skill->dbs->db[idx].inf2; if ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || @@ -7087,7 +7279,7 @@ int pc_allskillup(struct map_session_data *sd) continue; //Cannot be learned normally. sd->status.skill[idx].id = id; - sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_); // celest + sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class); // celest } } status_calc_pc(sd,SCO_NONE); @@ -7124,7 +7316,7 @@ int pc_resetlvl(struct map_session_data* sd,int type) sd->status.int_=1; sd->status.dex=1; sd->status.luk=1; - if(sd->status.class_ == JOB_NOVICE_HIGH) { + if (sd->status.class == JOB_NOVICE_HIGH) { sd->status.status_point=100; // not 88 [celest] // give platinum skills upon changing pc->skill(sd, NV_FIRSTAID, 1, SKILL_GRANT_PERMANENT); @@ -7201,7 +7393,7 @@ int pc_resetstate(struct map_session_data* sd) return 0; } - sd->status.status_point = pc->statp[sd->status.base_level] + ((sd->class_&JOBL_UPPER) ? 52 : 0); // extra 52+48=100 stat points + sd->status.status_point = pc->statp[sd->status.base_level] + ((sd->job & JOBL_UPPER) != 0 ? 52 : 0); // extra 52+48=100 stat points } else { @@ -7259,7 +7451,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) int i, inf2, skill_point=0; nullpo_ret(sd); - if( flag&PCRESETSKILL_CHSEX && (sd->class_&MAPID_UPPERMASK) != MAPID_BARDDANCER ) + if (flag&PCRESETSKILL_CHSEX && (sd->job & MAPID_UPPERMASK) != MAPID_BARDDANCER) return 0; if( !(flag&PCRESETSKILL_RECOUNT) ) { //Remove stuff lost when resetting skills. @@ -7267,7 +7459,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) /** * 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) **/ - if( (sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) ) + if ((sd->job & MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->fame_rank(sd->status.char_id, RANKTYPE_TAEKWON)) return 0; if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex] @@ -7283,7 +7475,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) i &= ~OPTION_WUG; if( i&OPTION_WUGRIDER && pc->checkskill(sd, RA_WUGRIDER) ) i &= ~OPTION_WUGRIDER; - if( i&OPTION_MADOGEAR && ( sd->class_&MAPID_THIRDMASK ) == MAPID_MECHANIC ) + if (i&OPTION_MADOGEAR && (sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) i &= ~OPTION_MADOGEAR; #ifndef NEW_CARTS if( i&OPTION_CART && pc->checkskill(sd, MC_PUSHCART) ) @@ -7297,6 +7489,9 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) ) homun->vaporize(sd, HOM_ST_REST); + + if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE))) + status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER); } for( i = 1; i < MAX_SKILL; i++ ) { @@ -7314,14 +7509,16 @@ int pc_resetskill(struct map_session_data* sd, int flag) skill_id = skill->dbs->db[i].nameid; // Don't reset trick dead if not a novice/baby - if( skill_id == NV_TRICKDEAD && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) { + if (skill_id == NV_TRICKDEAD && (sd->job & MAPID_UPPERMASK) != MAPID_NOVICE) { sd->status.skill[i].lv = 0; sd->status.skill[i].flag = 0; continue; } // do not reset basic skill - if( skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) + if (skill_id == NV_BASIC && (sd->job & MAPID_UPPERMASK) != MAPID_NOVICE) + continue; + if (skill_id == SU_BASIC_SKILL && (sd->job & MAPID_BASEMASK) != MAPID_SUMMONER) continue; if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) @@ -7420,22 +7617,42 @@ int pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id) return bonus; } -int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) { +int pc_skillheal_bonus(struct map_session_data *sd, uint16 skill_id) +{ int i, bonus = sd->bonus.add_heal_rate; - if( bonus ) { - switch( skill_id ) { - case AL_HEAL: if( !(battle_config.skill_add_heal_rate&1) ) bonus = 0; break; - case PR_SANCTUARY: if( !(battle_config.skill_add_heal_rate&2) ) bonus = 0; break; - case AM_POTIONPITCHER: if( !(battle_config.skill_add_heal_rate&4) ) bonus = 0; break; - case CR_SLIMPITCHER: if( !(battle_config.skill_add_heal_rate&8) ) bonus = 0; break; - case BA_APPLEIDUN: if( !(battle_config.skill_add_heal_rate&16)) bonus = 0; break; + if (bonus) { + switch (skill_id) { + case AL_HEAL: + if ((battle_config.skill_add_heal_rate & 1) == 0) + bonus = 0; + break; + case PR_SANCTUARY: + if ((battle_config.skill_add_heal_rate & 2) == 0) + bonus = 0; + break; + case AM_POTIONPITCHER: + if ((battle_config.skill_add_heal_rate & 4) == 0) + bonus = 0; + break; + case CR_SLIMPITCHER: + if ((battle_config.skill_add_heal_rate & 8) == 0) + bonus = 0; + break; + case BA_APPLEIDUN: + if ((battle_config.skill_add_heal_rate & 16) == 0) + bonus = 0; + break; + case AB_HIGHNESSHEAL: + if ((battle_config.skill_add_heal_rate & 32) == 0) + bonus = 0; + break; } } ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == skill_id); - if( i < ARRAYLENGTH(sd->skillheal) ) + if (i < ARRAYLENGTH(sd->skillheal)) bonus += sd->skillheal[i].val; return bonus; @@ -7504,7 +7721,8 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h if( sd->status.ele_id > 0 ) elemental->set_target(sd,src); - sd->canlog_tick = timer->gettick(); + if (battle_config.prevent_logout_trigger & PLT_DAMAGE) + sd->canlog_tick = timer->gettick(); } /*========================================== @@ -7620,7 +7838,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { if (md->target_id==sd->bl.id) mob->unlocktarget(md,tick); if (battle_config.mobs_level_up && md->status.hp - && (unsigned int)md->level < pc->maxbaselv(sd) + && md->level < pc->maxbaselv(sd) && !md->guardian_data && md->special_state.ai == AI_NONE// Guardians/summons should not level. [Skotlex] ) { // monster level up [Valaris] @@ -7699,7 +7917,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } // activate Steel body if a super novice dies at 99+% exp [celest] - if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) { + if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) { unsigned int next = pc->nextbaseexp(sd); if( next == 0 ) next = pc->thisbaseexp(sd); if( get_percentage(sd->status.base_exp,next) >= 99 ) { @@ -7718,7 +7936,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { // changed penalty options, added death by player if pk_mode [Valaris] if( battle_config.death_penalty_type - && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty + && (sd->job & MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty && !map->list[sd->bl.m].flag.noexppenalty && !map_flag_gvg2(sd->bl.m) && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY] ) { @@ -7867,6 +8085,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { + nullpo_retv(sd); if(hp) clif->updatestatus(sd,SP_HP); if(sp) clif->updatestatus(sd,SP_SP); @@ -7886,7 +8105,7 @@ void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { /*========================================== * script reading pc status registry *------------------------------------------*/ -int pc_readparam(struct map_session_data* sd,int type) +int pc_readparam(const struct map_session_data *sd, int type) { int val = 0; @@ -7896,12 +8115,13 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_SKILLPOINT: val = sd->status.skill_point; break; case SP_STATUSPOINT: val = sd->status.status_point; break; case SP_ZENY: val = sd->status.zeny; break; + case SP_BANKVAULT: val = sd->status.bank_vault; break; case SP_BASELEVEL: val = sd->status.base_level; break; case SP_JOBLEVEL: val = sd->status.job_level; break; - case SP_CLASS: val = sd->status.class_; break; - case SP_BASEJOB: val = pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex); break; //Base job, extracting upper type. - case SP_UPPER: val = (sd->class_&JOBL_UPPER) ? 1 : ((sd->class_&JOBL_BABY) ? 2 : 0); break; - case SP_BASECLASS: val = pc->mapid2jobid(sd->class_&MAPID_BASEMASK, sd->status.sex); break; //Extract base class tree. [Skotlex] + case SP_CLASS: val = sd->status.class; break; + case SP_BASEJOB: val = pc->mapid2jobid(sd->job & MAPID_UPPERMASK, sd->status.sex); break; //Base job, extracting upper type. + case SP_UPPER: val = (sd->job & JOBL_UPPER) != 0 ? 1 : ((sd->job & JOBL_BABY) != 0 ? 2 : 0); break; + case SP_BASECLASS: val = pc->mapid2jobid(sd->job & MAPID_BASEMASK, sd->status.sex); break; //Extract base class tree. [Skotlex] case SP_SEX: val = sd->status.sex; break; case SP_WEIGHT: val = sd->weight; break; case SP_MAXWEIGHT: val = sd->max_weight; break; @@ -7944,7 +8164,7 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_VARCASTRATE: #endif case SP_CASTRATE: - val = sd->castrate+=val; + val = sd->castrate; break; case SP_MAXHPRATE: val = sd->hprate; break; case SP_MAXSPRATE: val = sd->sprate; break; @@ -8040,19 +8260,20 @@ int pc_readparam(struct map_session_data* sd,int type) *------------------------------------------*/ int pc_setparam(struct map_session_data *sd,int type,int val) { + int delta; nullpo_ret(sd); switch(type){ case SP_BASELEVEL: - if ((unsigned int)val > pc->maxbaselv(sd)) //Capping to max + if (val > pc->maxbaselv(sd)) //Capping to max val = pc->maxbaselv(sd); - if ((unsigned int)val > sd->status.base_level) { + if (val > sd->status.base_level) { int stat = 0, i; - for (i = 0; i < (int)((unsigned int)val - sd->status.base_level); i++) + for (i = 0; i < val - sd->status.base_level; i++) stat += pc->gets_status_point(sd->status.base_level + i); sd->status.status_point += stat; } - sd->status.base_level = (unsigned int)val; + sd->status.base_level = val; sd->status.base_exp = 0; // clif->updatestatus(sd, SP_BASELEVEL); // Gets updated at the bottom clif->updatestatus(sd, SP_NEXTBASEEXP); @@ -8065,12 +8286,13 @@ int pc_setparam(struct map_session_data *sd,int type,int val) } break; case SP_JOBLEVEL: - if ((unsigned int)val >= sd->status.job_level) { - if ((unsigned int)val > pc->maxjoblv(sd)) val = pc->maxjoblv(sd); + if (val >= sd->status.job_level) { + if (val > pc->maxjoblv(sd)) + val = pc->maxjoblv(sd); sd->status.skill_point += val - sd->status.job_level; clif->updatestatus(sd, SP_SKILLPOINT); } - sd->status.job_level = (unsigned int)val; + sd->status.job_level = val; sd->status.job_exp = 0; // clif->updatestatus(sd, SP_JOBLEVEL); // Gets updated at the bottom clif->updatestatus(sd, SP_NEXTJOBEXP); @@ -8089,6 +8311,19 @@ int pc_setparam(struct map_session_data *sd,int type,int val) logs->zeny(sd, LOG_TYPE_SCRIPT, sd, -(sd->status.zeny - cap_value(val, 0, MAX_ZENY))); sd->status.zeny = cap_value(val, 0, MAX_ZENY); break; + case SP_BANKVAULT: + val = cap_value(val, 0, MAX_BANK_ZENY); + delta = (val - sd->status.bank_vault); + sd->status.bank_vault = val; + if (map->save_settings & 256) { + chrif->save(sd, 0); // send to char server + } + if (delta > 0) { + clif->bank_deposit(sd, BDA_SUCCESS); + } else if (delta < 0) { + clif->bank_withdraw(sd, BWA_SUCCESS); + } + return 1; // the vault uses a different packet case SP_BASEEXP: if(pc->nextbaseexp(sd) > 0) { sd->status.base_exp = val; @@ -8202,6 +8437,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) *------------------------------------------*/ void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int type) { + nullpo_retv(sd); if (type) { if (hp) clif->heal(sd->fd,SP_HP,hp); @@ -8225,6 +8461,7 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) { int bonus, tmp; + nullpo_ret(sd); if(hp) { int i; bonus = 100 + (sd->battle_status.vit<<1) @@ -8291,6 +8528,9 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) if( sd->sc.data[SC_EXTREMITYFIST2] ) sp = 0; #endif + if (sd->sc.data[SC_BITESCAR]) { + hp = 0; + } } return status->heal(&sd->bl, hp, sp, 1); @@ -8353,46 +8593,45 @@ int jobchange_killclone(struct block_list *bl, va_list ap) * Called when player changes job * Rewrote to make it tidider [Celest] *------------------------------------------*/ -int pc_jobchange(struct map_session_data *sd,int job, int upper) +int pc_jobchange(struct map_session_data *sd, int class, int upper) { int i, fame_flag=0; - int b_class, idx = 0; + int job, idx = 0; nullpo_ret(sd); - if (job < 0) + if (class < 0) return 1; //Normalize job. - b_class = pc->jobid2mapid(job); - if (b_class == -1) + job = pc->jobid2mapid(class); + if (job == -1) return 1; switch (upper) { case 1: - b_class|= JOBL_UPPER; + job |= JOBL_UPPER; break; case 2: - b_class|= JOBL_BABY; + job |= JOBL_BABY; break; } //This will automatically adjust bard/dancer classes to the correct gender //That is, if you try to jobchange into dancer, it will turn you to bard. - job = pc->mapid2jobid(b_class, sd->status.sex); - if (job == -1) + class = pc->mapid2jobid(job, sd->status.sex); + if (class == -1) return 1; - if ((unsigned short)b_class == sd->class_) + if ((uint16)job == sd->job) return 1; //Nothing to change. - // changing from 1st to 2nd job - if ((b_class&JOBL_2) && !(sd->class_&JOBL_2) && (b_class&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) { + if ((job & JOBL_2) != 0 && (sd->job & JOBL_2) == 0 && (job & MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) { + // changing from 1st to 2nd job sd->change_level_2nd = sd->status.job_level; - pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd); - } - // changing from 2nd to 3rd job - else if((b_class&JOBL_THIRD) && !(sd->class_&JOBL_THIRD)) { + pc_setglobalreg(sd, script->add_str("jobchange_level"), sd->change_level_2nd); + } else if((job & JOBL_THIRD) != 0 && (sd->job & JOBL_THIRD) == 0) { + // changing from 2nd to 3rd job sd->change_level_3rd = sd->status.job_level; - pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); + pc_setglobalreg(sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); } if(sd->cloneskill_id) { @@ -8421,10 +8660,10 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL_LV"),0); } - if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree. - const int class_ = pc->class2idx(sd->status.class_); + if ((job & MAPID_UPPERMASK) != (sd->job & MAPID_UPPERMASK)) { //Things to remove when changing class tree. + const int class_idx = pc->class2idx(sd->status.class); short id; - for(i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[class_][i].id) > 0; i++) { + for (i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[class_idx][i].id) > 0; i++) { //Remove status specific to your current tree skills. enum sc_type sc = status->skill2sc(id); if (sc > SC_COMMON_MAX && sd->sc.data[sc]) @@ -8432,14 +8671,18 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) } } - if( (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && (b_class&MAPID_UPPERMASK) != MAPID_STAR_GLADIATOR) { + if ((sd->job & MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && (job & MAPID_UPPERMASK) != MAPID_STAR_GLADIATOR) { /* going off star glad lineage, reset feel to not store no-longer-used vars in the database */ pc->resetfeel(sd); } - sd->status.class_ = job; - fame_flag = pc->famerank(sd->status.char_id,sd->class_&MAPID_UPPERMASK); - sd->class_ = (unsigned short)b_class; + sd->status.class = class; + { + int fame_list_type = pc->famelist_type(sd->job); + if (fame_list_type != RANKTYPE_UNKNOWN) + fame_flag = pc->fame_rank(sd->status.char_id, fame_list_type); + } + sd->job = (uint16)job; sd->status.job_level=1; sd->status.job_exp=0; @@ -8468,8 +8711,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) if (sd->disguise != -1) pc->disguise(sd, -1); - status->set_viewdata(&sd->bl, job); - clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); // move sprite update to prevent client crashes with incompatible equipment [Valaris] + status->set_viewdata(&sd->bl, class); + clif->changelook(&sd->bl, LOOK_BASE, sd->vd.class); // move sprite update to prevent client crashes with incompatible equipment [Valaris] if(sd->vd.cloth_color) clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); if (sd->vd.body_style) @@ -8488,7 +8731,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) //Remove peco/cart/falcon i = sd->sc.option; - if( i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) ) + if (i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->job & MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT)) i&=~OPTION_RIDING; if( i&OPTION_FALCON && !pc->checkskill(sd, HT_FALCON) ) i&=~OPTION_FALCON; @@ -8513,6 +8756,9 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN)) homun->vaporize(sd, HOM_ST_REST); + if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE))) + status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER); + if(sd->status.manner < 0) clif->changestatus(sd,SP_MANNER,sd->status.manner); @@ -8521,12 +8767,12 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) pc->equiplookall(sd); //if you were previously famous, not anymore. - if (fame_flag) { + if (fame_flag != 0) { chrif->save(sd,0); chrif->buildfamelist(); } else if (sd->status.fame > 0) { //It may be that now they are famous? - switch (sd->class_&MAPID_UPPERMASK) { + switch (sd->job & MAPID_UPPERMASK) { case MAPID_BLACKSMITH: case MAPID_ALCHEMIST: case MAPID_TAEKWON: @@ -8566,7 +8812,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) switch(type){ case LOOK_BASE: status->set_viewdata(&sd->bl, val); - clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); + clif->changelook(&sd->bl, LOOK_BASE, sd->vd.class); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); if (sd->vd.cloth_color) clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); @@ -8712,8 +8958,8 @@ int pc_setoption(struct map_session_data *sd,int type) return 0; //Disguises break sprite changes if (new_look < 0) { //Restore normal look. - status->set_viewdata(&sd->bl, sd->status.class_); - new_look = sd->vd.class_; + status->set_viewdata(&sd->bl, sd->status.class); + new_look = sd->vd.class; } pc_stop_attack(sd); //Stop attacking on new view change (to prevent wedding/santa attacks. @@ -8795,6 +9041,7 @@ int pc_setcart(struct map_session_data *sd,int type) { **/ void pc_setfalcon(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd,HT_FALCON) > 0) // add falcon if he have the skill pc->setoption(sd,sd->sc.option|OPTION_FALCON); @@ -8813,6 +9060,7 @@ void pc_setfalcon(struct map_session_data *sd, bool flag) **/ void pc_setridingpeco(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd, KN_RIDING)) pc->setoption(sd, sd->sc.option|OPTION_RIDING); @@ -8831,8 +9079,9 @@ void pc_setridingpeco(struct map_session_data *sd, bool flag) **/ void pc_setmadogear(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { - if ((sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC) + if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR); } else if (pc_ismadogear(sd)) { pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR); @@ -8849,6 +9098,7 @@ void pc_setmadogear(struct map_session_data *sd, bool flag) **/ void pc_setridingdragon(struct map_session_data *sd, unsigned int type) { + nullpo_retv(sd); if (type&OPTION_DRAGON) { // Ensure only one dragon is set at a time. if (type&OPTION_DRAGON1) @@ -8881,6 +9131,7 @@ void pc_setridingdragon(struct map_session_data *sd, unsigned int type) **/ void pc_setridingwug(struct map_session_data *sd, bool flag) { + nullpo_retv(sd); if (flag) { if (pc->checkskill(sd, RA_WUGRIDER) > 0) pc->setoption(sd,sd->sc.option|OPTION_WUGRIDER); @@ -8948,6 +9199,7 @@ int pc_candrop(struct map_session_data *sd, struct item *item) * For '@type' variables (temporary numeric char reg) **/ int pc_readreg(struct map_session_data* sd, int64 reg) { + nullpo_ret(sd); return i64db_iget(sd->regs.vars, reg); } /** @@ -8956,6 +9208,7 @@ int pc_readreg(struct map_session_data* sd, int64 reg) { void pc_setreg(struct map_session_data* sd, int64 reg, int val) { unsigned int index = script_getvaridx(reg); + nullpo_retv(sd); if( val ) { i64db_iput(sd->regs.vars, reg, val); if( index ) @@ -8973,6 +9226,7 @@ void pc_setreg(struct map_session_data* sd, int64 reg, int val) { char* pc_readregstr(struct map_session_data* sd, int64 reg) { struct script_reg_str *p = NULL; + nullpo_retr(NULL, sd); p = i64db_get(sd->regs.vars, reg); return p ? p->value : NULL; @@ -8983,8 +9237,10 @@ char* pc_readregstr(struct map_session_data* sd, int64 reg) { void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { struct script_reg_str *p = NULL; unsigned int index = script_getvaridx(reg); - DBData prev; + struct DBData prev; + nullpo_retv(sd); + nullpo_retv(str); if( str[0] ) { p = ers_alloc(pc->str_reg_ers, struct script_reg_str); @@ -9020,6 +9276,7 @@ void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { int pc_readregistry(struct map_session_data *sd, int64 reg) { struct script_reg_num *p = NULL; + nullpo_ret(sd); if (!sd->vars_ok) { ShowError("pc_readregistry: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg))); //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again. @@ -9041,6 +9298,7 @@ int pc_readregistry(struct map_session_data *sd, int64 reg) { char* pc_readregistry_str(struct map_session_data *sd, int64 reg) { struct script_reg_str *p = NULL; + nullpo_retr(NULL, sd); if (!sd->vars_ok) { ShowError("pc_readregistry_str: Trying to read reg %s before it's been loaded!\n", script->get_str(script_getvarid(reg))); //This really shouldn't happen, so it's possible the data was lost somewhere, we should request it again. @@ -9064,11 +9322,12 @@ int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { const char *regname = script->get_str( script_getvarid(reg) ); unsigned int index = script_getvaridx(reg); + nullpo_ret(sd); /* SAAD! those things should be stored elsewhere e.g. char ones in char table, the cash ones in account_data table! */ switch( regname[0] ) { default: //Char reg if( !strcmp(regname,"PC_DIE_COUNTER") && sd->die_counter != val ) { - int i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); + int i = (!sd->die_counter && (sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); sd->die_counter = val; if( i ) status_calc_pc(sd,SCO_NONE); // Lost the bonus. @@ -9106,7 +9365,7 @@ int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { if( !pc->reg_load ) p->flag.update = 1;/* either way, it will require either delete or replace */ } else if( val ) { - DBData prev; + struct DBData prev; if( index ) script->array_update(&sd->regs, reg, false); @@ -9139,6 +9398,8 @@ int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) const char *regname = script->get_str( script_getvarid(reg) ); unsigned int index = script_getvaridx(reg); + nullpo_ret(sd); + nullpo_ret(val); if ( !pc->reg_load && !sd->vars_ok ) { ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname); return 0; @@ -9159,7 +9420,7 @@ int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) if( !pc->reg_load ) p->flag.update = 1;/* either way, it will require either delete or replace */ } else if( val[0] ) { - DBData prev; + struct DBData prev; if( index ) script->array_update(&sd->regs, reg, false); @@ -9216,6 +9477,7 @@ int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name) { int i; nullpo_ret(sd); + nullpo_ret(name); ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] == INVALID_TIMER ); if( i == MAX_EVENTTIMER ) @@ -9236,6 +9498,7 @@ int pc_deleventtimer(struct map_session_data *sd,const char *name) int i; nullpo_ret(sd); + nullpo_ret(name); if (sd->eventcount <= 0) return 0; @@ -9304,6 +9567,8 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int index, success = 0; struct pc_combos *combo; + nullpo_ret(sd); + nullpo_ret(data); for( i = 0; i < data->combos_count; i++ ) { /* ensure this isn't a duplicate combo */ @@ -9379,6 +9644,8 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { int i, retval = 0; + nullpo_ret(sd); + nullpo_ret(data); if( !sd->combos ) return 0;/* nothing to do here, player has no combos */ @@ -9423,6 +9690,7 @@ int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { } int pc_load_combo(struct map_session_data *sd) { int i, ret = 0; + nullpo_ret(sd); for( i = 0; i < EQI_MAX; i++ ) { struct item_data *id = NULL; int idx = sd->equip_index[i]; @@ -9455,6 +9723,7 @@ int pc_load_combo(struct map_session_data *sd) { **/ void pc_equipitem_pos(struct map_session_data *sd, struct item_data *id, int n, int pos) { + nullpo_retv(sd); if ((!map_no_view(sd->bl.m,EQP_SHADOW_WEAPON) && pos & EQP_SHADOW_WEAPON) || (pos & EQP_HAND_R)) { if(id) @@ -9565,8 +9834,8 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) pos = pc->equippoint(sd,n); //With a few exceptions, item should go in all specified slots. if(battle_config.battle_log) - ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos); - if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris] + ShowInfo("equip %d(%d) %x:%x\n", sd->status.inventory[n].nameid, n, (unsigned int)(id ? id->equip : 0), (unsigned int)req_pos); + if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ) { // [Valaris] // FIXME: pc->isequip: equip level failure uses 2 instead of 0 clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; @@ -9685,6 +9954,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) **/ void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos) { + nullpo_retv(sd); if (pos & EQP_HAND_R) { sd->weapontype1 = 0; sd->status.weapon = sd->weapontype2; @@ -9749,127 +10019,142 @@ void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos) *------------------------------------------*/ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { - int i,iflag; - bool status_cacl = false; + int i, iflag; + bool status_calc = false; int pos; + nullpo_ret(sd); - if( n < 0 || n >= MAX_INVENTORY ) { - clif->unequipitemack(sd,0,0,UIA_FAIL); + if (n < 0 || n >= MAX_INVENTORY) { + clif->unequipitemack(sd, 0, 0, UIA_FAIL); return 0; } // if player is berserk then cannot unequip - if (!(flag&PCUNEQUIPITEM_FORCE) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) ) - { - clif->unequipitemack(sd,n,0,UIA_FAIL); + if (!(flag & PCUNEQUIPITEM_FORCE) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP])) { + clif->unequipitemack(sd, n, 0, UIA_FAIL); return 0; } - if( !(flag&PCUNEQUIPITEM_FORCE) && sd->sc.count && sd->sc.data[SC_KYOUGAKU] ) - { - clif->unequipitemack(sd,n,0,UIA_FAIL); + if (!(flag & PCUNEQUIPITEM_FORCE) && sd->sc.count && sd->sc.data[SC_KYOUGAKU]) { + clif->unequipitemack(sd, n, 0, UIA_FAIL); return 0; } - if(battle_config.battle_log) - ShowInfo("unequip %d %x:%x\n",n,pc->equippoint(sd,n),sd->status.inventory[n].equip); + if (battle_config.battle_log) + ShowInfo("unequip %d %x:%x\n", n, (unsigned int)(pc->equippoint(sd, n)), sd->status.inventory[n].equip); - if(!sd->status.inventory[n].equip){ //Nothing to unequip - clif->unequipitemack(sd,n,0,UIA_FAIL); + if (sd->status.inventory[n].equip == 0) { //Nothing to unequip + clif->unequipitemack(sd, n, 0, UIA_FAIL); return 0; } - for(i=0;i<EQI_MAX;i++) { - if(sd->status.inventory[n].equip & pc->equip_pos[i]) + + for (i = 0; i < EQI_MAX; i++) { + if (sd->status.inventory[n].equip & pc->equip_pos[i]) sd->equip_index[i] = -1; } pos = sd->status.inventory[n].equip; pc->unequipitem_pos(sd, n, pos); - clif->unequipitemack(sd,n,pos,UIA_SUCCESS); + clif->unequipitemack(sd, n, pos, UIA_SUCCESS); - if((pos & EQP_ARMS) && - 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!) - skill->enchant_elemental_end(&sd->bl,-1); + if ((pos & EQP_ARMS) && + sd->weapontype1 == 0 && sd->weapontype2 == 0 && (sd->sc.data[SC_TK_SEVENWIND] == 0 || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) + skill->enchant_elemental_end(&sd->bl, -1); - if(pos & EQP_ARMOR) { + if (pos & EQP_ARMOR) { // On Armor Change... status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER); status_change_end(&sd->bl, SC_ARMOR_RESIST, INVALID_TIMER); } +#ifdef RENEWAL + if (battle->bc->bow_unequip_arrow && pos&EQP_ARMS && sd->equip_index[EQI_AMMO] > 0) + pc->unequipitem(sd, sd->equip_index[EQI_AMMO], PCUNEQUIPITEM_FORCE); +#endif + if( sd->state.autobonus&pos ) sd->state.autobonus &= ~sd->status.inventory[n].equip; //Check for activated autobonus [Inkfish] - sd->status.inventory[n].equip=0; + sd->status.inventory[n].equip = 0; iflag = sd->npc_item_flag; /* check for combos (MUST be before status_calc_pc) */ - if ( sd->inventory_data[n] ) { - if( sd->inventory_data[n]->combos_count ) { - if( pc->removecombo(sd,sd->inventory_data[n]) ) - status_cacl = true; - } if(itemdb_isspecial(sd->status.inventory[n].card[0])) - ; //No cards - else { - for( i = 0; i < sd->inventory_data[n]->slot; i++ ) { + if (sd->inventory_data[n] != NULL) { + if (sd->inventory_data[n]->combos_count) { + if (pc->removecombo(sd, sd->inventory_data[n])) + status_calc = true; + } + if (itemdb_isspecial(sd->status.inventory[n].card[0]) == false) { + for (i = 0; i < sd->inventory_data[n]->slot; i++) { struct item_data *data; - if (!sd->status.inventory[n].card[i]) + if (sd->status.inventory[n].card[i] == 0) continue; - if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { - if( data->combos_count ) { - if( pc->removecombo(sd,data) ) - status_cacl = true; + if ((data = itemdb->exists(sd->status.inventory[n].card[i])) != NULL) { + if (data->combos_count) { + if (pc->removecombo(sd, data)) + status_calc = true; } } } } + /* Item Options checking */ + for (i = 0; i < MAX_ITEM_OPTIONS; i++) { + struct item_option *ito = NULL; + int16 item_option = sd->status.inventory[n].option[i].index; + + if (item_option <= 0) + continue; + if ((ito = itemdb->option_exists(sd->status.inventory[n].option[i].index)) == NULL) + continue; + + status_calc = true; + } } - if(flag&PCUNEQUIPITEM_RECALC || status_cacl) { + if (flag & PCUNEQUIPITEM_RECALC || status_calc) { pc->checkallowskill(sd); - status_calc_pc(sd,SCO_NONE); + status_calc_pc(sd, SCO_NONE); } - if(sd->sc.data[SC_CRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele)) + if (sd->sc.data[SC_CRUCIS] && battle->check_undead(sd->battle_status.race, sd->battle_status.def_ele) == false) status_change_end(&sd->bl, SC_CRUCIS, INVALID_TIMER); //OnUnEquip script [Skotlex] - if (sd->inventory_data[n]) { - if (sd->inventory_data[n]->unequip_script) { - if ( battle_config.unequip_restricted_equipment & 1 ) { - 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); - if ( i == map->list[sd->bl.m].zone->disabled_items_count ) + if (sd->inventory_data[n] != NULL) { + if (sd->inventory_data[n]->unequip_script != NULL) { + if (battle_config.unequip_restricted_equipment & 1) { + 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); + if (i == map->list[sd->bl.m].zone->disabled_items_count) script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id); } else script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id); } - if(itemdb_isspecial(sd->status.inventory[n].card[0])) - ; //No cards - else { - for( i = 0; i < sd->inventory_data[n]->slot; i++ ) { - struct item_data *data; - if (!sd->status.inventory[n].card[i]) + if (itemdb_isspecial(sd->status.inventory[n].card[0]) == false) { + for (i = 0; i < sd->inventory_data[n]->slot; i++) { + struct item_data *data = NULL; + if (sd->status.inventory[n].card[i] == 0) continue; - if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { - if ( data->unequip_script ) { - if ( battle_config.unequip_restricted_equipment & 2 ) { + if ((data = itemdb->exists(sd->status.inventory[n].card[i])) != NULL) { + if (data->unequip_script) { + if (battle_config.unequip_restricted_equipment & 2) { int j; - 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]); - if ( j == map->list[sd->bl.m].zone->disabled_items_count ) + 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]); + if (j == map->list[sd->bl.m].zone->disabled_items_count) script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id); - } - else + } else { script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id); + } } } } } } + sd->npc_item_flag = iflag; return 1; @@ -9885,99 +10170,108 @@ int pc_checkitem(struct map_session_data *sd) nullpo_ret(sd); - if (sd->state.vending) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam) + if (sd->state.vending == 1) // Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam) return 0; - if (sd->state.itemcheck) { // check for invalid(ated) items - int id; - for (i = 0; i < MAX_INVENTORY; i++) { - id = sd->status.inventory[i].nameid; + if (sd->itemcheck != PCCHECKITEM_NONE) { // check for invalid(ated) items + int id = 0; - if (!id) - continue; + if (sd->itemcheck & PCCHECKITEM_INVENTORY) { + for (i = 0; i < MAX_INVENTORY; i++) { + if ((id = sd->status.inventory[i].nameid) == 0) + continue; - if (!itemdb_available(id)) { - 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); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); - continue; + if (!itemdb_available(id)) { + ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_INV_INVALID); + continue; + } + + if (sd->status.inventory[i].unique_id == 0 && !itemdb->isstackable(id)) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); } - if (!sd->status.inventory[i].unique_id && !itemdb->isstackable(id)) - sd->status.inventory[i].unique_id = itemdb->unique_id(sd); + sd->itemcheck &= ~PCCHECKITEM_INVENTORY; } - for( i = 0; i < MAX_CART; i++ ) { - id = sd->status.cart[i].nameid; + if (sd->itemcheck & PCCHECKITEM_CART) { + for (i = 0; i < MAX_CART; i++) { + if ((id = sd->status.cart[i].nameid) == 0) + continue; - if (!id) - continue; + if( !itemdb_available(id) ) { + ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id); + pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_CART_INVALID); + continue; + } - if( !itemdb_available(id) ) { - 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); - pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER); - continue; + if (sd->status.cart[i].unique_id == 0 && !itemdb->isstackable(id)) + sd->status.cart[i].unique_id = itemdb->unique_id(sd); } - if ( !sd->status.cart[i].unique_id && !itemdb->isstackable(id) ) - sd->status.cart[i].unique_id = itemdb->unique_id(sd); + sd->itemcheck &= ~PCCHECKITEM_CART; } - for( i = 0; i < MAX_STORAGE; i++ ) { - id = sd->status.storage.items[i].nameid; + if (sd->itemcheck & PCCHECKITEM_STORAGE && sd->storage.received == true) { + for (i = 0; i < VECTOR_LENGTH(sd->storage.item); i++) { + struct item *it = &VECTOR_INDEX(sd->storage.item, i); - if (!id) - continue; + if ((id = it->nameid) == 0) + continue; - if( id && !itemdb_available(id) ) { - 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); - storage->delitem(sd, i, sd->status.storage.items[i].amount); - storage->close(sd); - continue; + if (!itemdb_available(id)) { + ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, it->amount, sd->status.char_id); + storage->delitem(sd, i, it->amount); + continue; + } + + if (it->unique_id == 0 && itemdb->isstackable(id) == 0) + it->unique_id = itemdb->unique_id(sd); } - if ( !sd->status.storage.items[i].unique_id && !itemdb->isstackable(id) ) - sd->status.storage.items[i].unique_id = itemdb->unique_id(sd); + storage->close(sd); + + sd->itemcheck &= ~PCCHECKITEM_STORAGE; } - if (sd->guild) { + if (sd->guild && sd->itemcheck & PCCHECKITEM_GSTORAGE) { struct guild_storage *guild_storage = idb_get(gstorage->db,sd->guild->guild_id); if (guild_storage) { - for( i = 0; i < MAX_GUILD_STORAGE; i++ ) { - id = guild_storage->items[i].nameid; - - if (!id) + for (i = 0; i < MAX_GUILD_STORAGE; i++) { + if ((id = guild_storage->items[i].nameid) == 0) continue; - if( !itemdb_available(id) ) { - 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); + if (!itemdb_available(id)) { + ShowWarning("pc_checkitem: 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); gstorage->delitem(sd, guild_storage, i, guild_storage->items[i].amount); gstorage->close(sd); // force closing continue; } - if (!guild_storage->items[i].unique_id && !itemdb->isstackable(id)) + if (guild_storage->items[i].unique_id == 0 && !itemdb->isstackable(id)) guild_storage->items[i].unique_id = itemdb->unique_id(sd); } } + + sd->itemcheck &= ~PCCHECKITEM_GSTORAGE; } - sd->state.itemcheck = 0; } - for( i = 0; i < MAX_INVENTORY; i++) { + for (i = 0; i < MAX_INVENTORY; i++) { - if( sd->status.inventory[i].nameid == 0 ) + if (sd->status.inventory[i].nameid == 0) continue; - if( !sd->status.inventory[i].equip ) + if (sd->status.inventory[i].equip == 0) continue; - if( sd->status.inventory[i].equip&~pc->equippoint(sd,i) ) { + if (sd->status.inventory[i].equip & ~pc->equippoint(sd,i)) { pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); calc_flag = 1; continue; } - if (battle_config.unequip_restricted_equipment&1) { + if (battle_config.unequip_restricted_equipment & 1) { int j; for (j = 0; j < map->list[sd->bl.m].zone->disabled_items_count; j++) { if (map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[i].nameid) { @@ -9987,7 +10281,7 @@ int pc_checkitem(struct map_session_data *sd) } } - if (battle_config.unequip_restricted_equipment&2) { + if (battle_config.unequip_restricted_equipment & 2) { if (!itemdb_isspecial(sd->status.inventory[i].card[0])) { int j, slot; for (slot = 0; slot < MAX_SLOTS; slot++) { @@ -10003,9 +10297,9 @@ int pc_checkitem(struct map_session_data *sd) } - if( calc_flag && sd->state.active ) { + if (calc_flag != 0 && sd->state.active == 1) { pc->checkallowskill(sd); - status_calc_pc(sd,SCO_NONE); + status_calc_pc(sd, SCO_NONE); } return 0; @@ -10040,6 +10334,7 @@ int pc_calc_pvprank_sub(struct block_list *bl, va_list ap) int pc_calc_pvprank(struct map_session_data *sd) { int old; struct map_data *m; + nullpo_ret(sd); m=&map->list[sd->bl.m]; old=sd->pvp_rank; sd->pvp_rank=1; @@ -10094,7 +10389,7 @@ int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd) { if(sd == NULL || dstsd == NULL || sd->status.partner_id > 0 || dstsd->status.partner_id > 0 || - (sd->class_&JOBL_BABY) || (dstsd->class_&JOBL_BABY)) + (sd->job & JOBL_BABY) != 0 || (dstsd->job & JOBL_BABY) != 0) return -1; sd->status.partner_id = dstsd->status.char_id; dstsd->status.partner_id = sd->status.char_id; @@ -10132,9 +10427,9 @@ int pc_divorce(struct map_session_data *sd) for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F ) - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); if( p_sd->status.inventory[i].nameid == WEDDING_RING_M || p_sd->status.inventory[i].nameid == WEDDING_RING_F ) - pc->delitem(p_sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(p_sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_DIVORCE); } clif->divorced(sd, p_sd->status.name); @@ -10158,7 +10453,7 @@ struct map_session_data *pc_get_partner(struct map_session_data *sd) { * Get sd father charid. (Need to be baby) *------------------------------------------*/ struct map_session_data *pc_get_father(struct map_session_data *sd) { - if (sd && sd->class_&JOBL_BABY && sd->status.father > 0) + if (sd && (sd->job & JOBL_BABY) != 0 && sd->status.father > 0) // charid2sd returns NULL if not found return map->charid2sd(sd->status.father); @@ -10169,7 +10464,7 @@ struct map_session_data *pc_get_father(struct map_session_data *sd) { * Get sd mother charid. (Need to be baby) *------------------------------------------*/ struct map_session_data *pc_get_mother(struct map_session_data *sd) { - if (sd && sd->class_&JOBL_BABY && sd->status.mother > 0) + if (sd && (sd->job & JOBL_BABY) != 0 && sd->status.mother > 0) // charid2sd returns NULL if not found return map->charid2sd(sd->status.mother); @@ -10194,6 +10489,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) { int hp = 0, sp = 0; + nullpo_retv(sd); if( pc_isdead(sd) ) return; @@ -10227,6 +10523,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) void pc_regen (struct map_session_data *sd, unsigned int diff_tick) { int hp = 0, sp = 0; + nullpo_retv(sd); if (sd->hp_regen.value) { sd->hp_regen.tick += diff_tick; while (sd->hp_regen.tick >= sd->hp_regen.rate) { @@ -10304,6 +10601,7 @@ int pc_autosave(int tid, int64 tick, int id, intptr_t data) { } int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) { + nullpo_ret(sd); if (sd->state.night != map->night_flag && map->list[sd->bl.m].flag.nightenabled) { //Night/day state does not match. clif->status_change(&sd->bl, SI_SKE, map->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] sd->state.night = map->night_flag; @@ -10327,7 +10625,7 @@ int map_day_timer(int tid, int64 tick, int id, intptr_t data) { map->night_flag = 0; // 0=day, 1=night [Yor] map->foreachpc(pc->daynight_timer_sub); safestrncpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60), sizeof(tmp_soutput)); // The day has arrived! - intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); + intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -10347,7 +10645,7 @@ int map_night_timer(int tid, int64 tick, int id, intptr_t data) { map->night_flag = 1; // 0=day, 1=night [Yor] map->foreachpc(pc->daynight_timer_sub); safestrncpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59), sizeof(tmp_soutput)); // The night has fallen... - intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); + intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -10368,6 +10666,7 @@ void pc_overheat(struct map_session_data *sd, int val) { int heat = val, skill_lv, limit[] = { 10, 20, 28, 46, 66 }; + nullpo_retv(sd); if( !pc_ismadogear(sd) || sd->sc.data[SC_OVERHEAT] ) return; // already burning @@ -10393,6 +10692,7 @@ bool pc_isautolooting(struct map_session_data *sd, int nameid) { int i = 0; + nullpo_ret(sd); if (sd->state.autoloottype && sd->state.autoloottype&(1<<itemdb_type(nameid))) return true; @@ -10538,11 +10838,18 @@ void pc_del_charm(struct map_session_data *sd, int count, int type) clif->spiritcharm(sd); } -/*========================================== - * Renewal EXP/Itemdrop rate modifier base on level penalty - * 1=exp 2=itemdrop - *------------------------------------------*/ -int pc_level_penalty_mod(int diff, unsigned char race, unsigned short mode, int type) { + +/** + * Renewal EXP/Itemdrop rate modifier base on level penalty. + * + * @param diff Level difference. + * @param race Monster race. + * @param mode Monster mode. + * @param type Modifier type (1=exp 2=itemdrop) + * @return The percent rate modifier (100 = 100%) + */ +int pc_level_penalty_mod(int diff, unsigned char race, uint32 mode, int type) +{ #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int rate = 100, i; @@ -10574,6 +10881,7 @@ int pc_split_str(char *str,char **val,int num) { int i; + nullpo_ret(val); for (i=0; i<num && str; i++){ val[i] = str; str = strchr(str,','); @@ -10586,6 +10894,7 @@ int pc_split_str(char *str,char **val,int num) int pc_split_atoi(char* str, int* val, char sep, int max) { int i,j; + nullpo_ret(val); for (i=0; i<max; i++) { if (!str) break; val[i] = atoi(str); @@ -10603,6 +10912,7 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) { static int warning=0; int i,j; + nullpo_ret(val); for (i=0; i<max; i++) { double f; if (!str) break; @@ -10642,8 +10952,8 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) */ void pc_read_skill_tree(void) { - config_t skill_tree_conf; - config_setting_t *skt = NULL; + struct config_t skill_tree_conf; + struct config_setting_t *skt = NULL; char config_filename[128]; int i = 0; struct s_mapiterator *iter; @@ -10651,14 +10961,12 @@ void pc_read_skill_tree(void) bool loaded[CLASS_COUNT] = { false }; safesnprintf(config_filename, sizeof(config_filename), "%s/"DBPATH"skill_tree.conf", map->db_path); - if (libconfig->read_file(&skill_tree_conf, config_filename)) { - ShowError("can't read %s\n", config_filename); + if (!libconfig->load_file(&skill_tree_conf, config_filename)) return; - } // Foreach job while ((skt = libconfig->setting_get_elem(skill_tree_conf.root, i++))) { - config_setting_t *t = NULL; + struct config_setting_t *t = NULL; int job_idx; const char *job_name = config_setting_name(skt); int job_id = pc->check_job_name(job_name); @@ -10748,11 +11056,11 @@ void pc_read_skill_tree(void) } if ((t = libconfig->setting_get_member(skt, "skills")) != NULL) { int j = 0; - config_setting_t *sk = NULL; + struct config_setting_t *sk = NULL; // Foreach skill while ((sk = libconfig->setting_get_elem(t, j++)) != NULL) { int skill_id, sk_idx; - config_setting_t *rsk = NULL; + struct config_setting_t *rsk = NULL; const char *sk_name = config_setting_name(sk); struct skill_tree_entry *tree_entry = NULL; @@ -10857,6 +11165,7 @@ bool pc_readdb_levelpenalty(char* fields[], int columns, int current) { #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int type, race, diff; + nullpo_retr(false, fields); type = atoi(fields[0]); race = atoi(fields[1]); diff = atoi(fields[2]); @@ -10907,7 +11216,7 @@ int pc_readdb(void) { while(fgets(line, sizeof(line), fp)) { int jobs[CLASS_COUNT], job_count, job, job_id; int type; - unsigned int ui,maxlv; + int maxlv; char *split[4]; if(line[0]=='/' && line[1]=='/') continue; @@ -10929,7 +11238,7 @@ int pc_readdb(void) { } maxlv = atoi(split[0]); if (maxlv > MAX_LEVEL) { - ShowWarning("pc_readdb: Specified max level %u for job %d is beyond server's limit (%u).\n ", maxlv, job_id, MAX_LEVEL); + ShowWarning("pc_readdb: Specified max level %d for job %d is beyond server's limit (%d).\n ", maxlv, job_id, MAX_LEVEL); maxlv = MAX_LEVEL; } count++; @@ -10940,15 +11249,15 @@ int pc_readdb(void) { //The reasoning behind the -2 is this... if the max level is 5, then the array //should look like this: //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3. - while ((ui = pc->max_level[job][type]) >= 2 && pc->exp_table[job][type][ui-2] <= 0) + while ((i = pc->max_level[job][type]) >= 2 && pc->exp_table[job][type][i-2] <= 0) pc->max_level[job][type]--; if (pc->max_level[job][type] < maxlv) { - ShowWarning("pc_readdb: Specified max %u for job %d, but that job's exp table only goes up to level %u.\n", maxlv, job_id, pc->max_level[job][type]); + 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]); ShowInfo("Filling the missing values with the last exp entry.\n"); //Fill the requested values with the last entry. - ui = (pc->max_level[job][type] <= 2? 0: pc->max_level[job][type]-2); - for (; ui+2 < maxlv; ui++) - pc->exp_table[job][type][ui] = pc->exp_table[job][type][ui-1]; + i = (pc->max_level[job][type] <= 2 ? 0: pc->max_level[job][type]-2); + for (; i+2 < maxlv; i++) + pc->exp_table[job][type][i] = pc->exp_table[job][type][i-1]; pc->max_level[job][type] = maxlv; } //ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]); @@ -10961,7 +11270,7 @@ int pc_readdb(void) { job = pc->class2idx(job_id); memcpy(pc->exp_table[job][type], pc->exp_table[jobs[0]][type], sizeof(pc->exp_table[0][0])); pc->max_level[job][type] = maxlv; - //ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job_id, pc->max_level[job][type]); + //ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]); } } fclose(fp); @@ -11001,18 +11310,18 @@ int pc_readdb(void) { ShowError("can't read %s\n", line); return 1; } - while(fgets(line, sizeof(line), fp)) - { + while (fgets(line, sizeof(line), fp)) { char *split[10]; int lv,n; - if(line[0]=='/' && line[1]=='/') + if (line[0]=='/' && line[1]=='/') continue; - for(j=0,p=line;j<3 && p;j++){ - split[j]=p; - p=strchr(p,','); - if(p) *p++=0; + for (j = 0, p = line; j < 3 && p != NULL; j++) { + split[j] = p; + p = strchr(p,','); + if (p != NULL) + *p++ = 0; } - if( j < 2 ) + if (j < 2) continue; lv=atoi(split[0]); @@ -11024,8 +11333,8 @@ int pc_readdb(void) { if(line[0]=='/' && line[1]=='/') continue; - for ( j = ELE_NEUTRAL, p = line; j<n && j<ELE_MAX && p; j++ ) { - while(*p==32 && *p>0) + for (j = ELE_NEUTRAL, p = line; j < n && j < ELE_MAX && p != NULL; j++) { + while (*p == ' ') p++; battle->attr_fix_table[lv-1][i][j]=atoi(p); #ifndef RENEWAL @@ -11033,7 +11342,8 @@ int pc_readdb(void) { battle->attr_fix_table[lv-1][i][j] = 0; #endif p=strchr(p,','); - if(p) *p++=0; + if (p != NULL) + *p++ = 0; } i++; @@ -11088,9 +11398,9 @@ void pc_validate_levels(void) { if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER) continue; //Classes that do not need exp tables. j = pc->class2idx(i); - if (!pc->max_level[j][0]) + if (pc->max_level[j][0] == 0) ShowWarning("Class %s (%d) does not has a base exp table.\n", pc->job_name(i), i); - if (!pc->max_level[j][1]) + if (pc->max_level[j][1] == 0) ShowWarning("Class %s (%d) does not has a job exp table.\n", pc->job_name(i), i); } } @@ -11099,6 +11409,7 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { int i,cursor = 0; struct item_cd* cd = NULL; + nullpo_retv(sd); if( load ) { if( !(cd = idb_get(pc->itemcd_db, sd->status.char_id)) ) { // no skill cooldown is associated with this character @@ -11130,7 +11441,10 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { } void pc_bank_deposit(struct map_session_data *sd, int money) { - unsigned int limit_check = money+sd->status.bank_vault; + unsigned int limit_check; + + nullpo_retv(sd); + limit_check = money + sd->status.bank_vault; if( money <= 0 || limit_check > MAX_BANK_ZENY ) { clif->bank_deposit(sd,BDA_OVERFLOW); @@ -11150,8 +11464,10 @@ void pc_bank_deposit(struct map_session_data *sd, int money) { } } void pc_bank_withdraw(struct map_session_data *sd, int money) { - unsigned int limit_check = money+sd->status.zeny; + unsigned int limit_check; + nullpo_retv(sd); + limit_check = money + sd->status.zeny; if (money <= 0) { clif->bank_withdraw(sd,BWA_UNKNOWN_ERROR); return; @@ -11175,6 +11491,7 @@ void pc_bank_withdraw(struct map_session_data *sd, int money) { } /* status change data arrived from char-server */ void pc_scdata_received(struct map_session_data *sd) { + nullpo_retv(sd); pc->inventory_rentals(sd); clif->show_modifiers(sd); @@ -11182,7 +11499,7 @@ void pc_scdata_received(struct map_session_data *sd) { time_t exp_time = sd->expiration_time; char tmpstr[1024]; strftime(tmpstr, sizeof(tmpstr) - 1, msg_sd(sd,501), localtime(&exp_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S." - clif->wis_message(sd->fd, map->wisp_server_name, tmpstr, strlen(tmpstr)+1); + clif->wis_message(sd->fd, map->wisp_server_name, tmpstr, (int)strlen(tmpstr)); pc->expire_check(sd); } @@ -11223,6 +11540,7 @@ int pc_global_expiration_timer(int tid, int64 tick, int id, intptr_t data) { return 0; } void pc_expire_check(struct map_session_data *sd) { + nullpo_retv(sd); /* ongoing timer */ if( sd->expiration_tid != INVALID_TIMER ) return; @@ -11280,6 +11598,7 @@ void pc_autotrade_start(struct map_session_data *sd) { int i; char *data; + nullpo_retv(sd); 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)) Sql_ShowDebug(map->mysql_handle); @@ -11324,6 +11643,7 @@ void pc_autotrade_start(struct map_session_data *sd) { void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update_action action) { int i; + nullpo_retv(sd); /* either way, this goes down */ if( action != PAUC_START ) { if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'",map->autotrade_data_db,sd->status.char_id)) @@ -11349,13 +11669,13 @@ void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update )) Sql_ShowDebug(map->mysql_handle); } - /* yes we want it to fall */ + FALLTHROUGH case PAUC_REFRESH: for( i = 0; i < sd->vend_num; i++ ) { if( sd->vending[i].amount == 0 ) continue; - if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`char_id`,`itemkey`,`amount`,`price`) VALUES ('%d','%d','%d','%d')", + if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`char_id`,`itemkey`,`amount`,`price`) VALUES ('%d','%d','%d','%u')", map->autotrade_data_db, sd->status.char_id, sd->status.cart[sd->vending[i].index].id, @@ -11377,6 +11697,7 @@ void pc_autotrade_prepare(struct map_session_data *sd) { char title[MESSAGE_SIZE]; unsigned char sex; + nullpo_retv(sd); CREATE(data, struct autotrade_vending, 1); memcpy(data->vending, sd->vending, sizeof(sd->vending)); @@ -11423,6 +11744,7 @@ void pc_autotrade_populate(struct map_session_data *sd) { struct autotrade_vending *data; int i, j, k, cursor = 0; + nullpo_retv(sd); if( !(data = idb_get(pc->at_db,sd->status.char_id)) ) return; @@ -11462,8 +11784,10 @@ void pc_autotrade_populate(struct map_session_data *sd) { /** * @see DBApply */ -int pc_autotrade_final(DBKey key, DBData *data, va_list ap) { +int pc_autotrade_final(union DBKey key, struct DBData *data, va_list ap) +{ struct autotrade_vending* at_v = DB->data2ptr(data); + nullpo_ret(at_v); HPM->data_store_destroy(&at_v->hdata); return 0; } @@ -11476,16 +11800,17 @@ void pc_update_idle_time(struct map_session_data* sd, enum e_battle_config_idlet } //Checks if the given class value corresponds to a player class. [Skotlex] -//JOB_NOVICE isn't checked for class_ is supposed to be unsigned -bool pc_db_checkid(unsigned int class_) +//JOB_NOVICE isn't checked for class is supposed to be unsigned +bool pc_db_checkid(int class) { - return class_ < JOB_MAX_BASIC - || (class_ >= JOB_NOVICE_HIGH && class_ <= JOB_DARK_COLLECTOR ) - || (class_ >= JOB_RUNE_KNIGHT && class_ <= JOB_MECHANIC_T2 ) - || (class_ >= JOB_BABY_RUNE && class_ <= JOB_BABY_MECHANIC2 ) - || (class_ >= JOB_SUPER_NOVICE_E && class_ <= JOB_SUPER_BABY_E ) - || (class_ >= JOB_KAGEROU && class_ <= JOB_OBORO ) - || (class_ >= JOB_REBELLION && class_ < JOB_MAX ); + return class < JOB_MAX_BASIC + || (class >= JOB_NOVICE_HIGH && class <= JOB_DARK_COLLECTOR ) + || (class >= JOB_RUNE_KNIGHT && class <= JOB_MECHANIC_T2 ) + || (class >= JOB_BABY_RUNE && class <= JOB_BABY_MECHANIC2 ) + || (class >= JOB_SUPER_NOVICE_E && class <= JOB_SUPER_BABY_E ) + || (class >= JOB_KAGEROU && class <= JOB_OBORO ) + || (class == JOB_REBELLION) + || (class >= JOB_SUMMONER && class < JOB_MAX ); } /** @@ -11496,12 +11821,108 @@ bool pc_db_checkid(unsigned int class_) int pc_have_magnifier(struct map_session_data *sd) { int n; - n = pc->search_inventory(sd, ITEMID_MAGNIFIER); + n = pc->search_inventory(sd, ITEMID_SPECTACLES); if (n == INDEX_NOT_FOUND) - n = pc->search_inventory(sd, ITEMID_NOVICE_MAGNIFIER); + n = pc->search_inventory(sd, ITEMID_N_MAGNIFIER); return n; } +/** + * Checks if player have basic skills learned. + * @param sd Player Data + * @param level Required Level of Novice Skill + * @return bool true, if requirement is satisfied + */ +bool pc_check_basicskill(struct map_session_data *sd, int level) { + if (pc->checkskill(sd, NV_BASIC) >= level || pc->checkskill(sd, SU_BASIC_SKILL)) + return true; + return false; +} + +/** + * Verifies a chat message, searching for atcommands, checking if the sender + * character can chat, and updating the idle timer. + * + * @param sd The sender character. + * @param message The message text. + * @return Whether the message is a valid chat message. + */ +bool pc_process_chat_message(struct map_session_data *sd, const char *message) +{ + nullpo_retr(false, sd); + if (atcommand->exec(sd->fd, sd, message, true)) { + return false; + } + + if (!pc->can_talk(sd)) { + return false; + } + + if (battle_config.min_chat_delay != 0) { + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) { + return false; + } + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; + } + + pc->update_idle_time(sd, BCIDLE_CHAT); + + return true; +} + +/** + * Checks a chat message, scanning for the Super Novice prayer sequence. + * + * If a match is found, the angel is invoked or the counter is incremented as + * appropriate. + * + * @param sd The sender character. + * @param message The message text. + */ +void pc_check_supernovice_call(struct map_session_data *sd, const char *message) +{ + unsigned int next = pc->nextbaseexp(sd); + int percent = 0; + + nullpo_retv(sd); + nullpo_retv(message); + if ((sd->job & MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) + return; + if (next == 0) + next = pc->thisbaseexp(sd); + if (next == 0) + return; + + // 0%, 10%, 20%, ... + percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. ); + if ((battle_config.snovice_call_type != 0 || percent != 0) && (percent%100) == 0) { + // 10.0%, 20.0%, ..., 90.0% + switch (sd->state.snovice_call_flag) { + case 0: + if (strstr(message, msg_txt(1479))) // "Dear angel, can you hear my voice?" + sd->state.snovice_call_flag = 1; + break; + case 1: + { + char buf[256]; + snprintf(buf, 256, msg_txt(1480), sd->status.name); + if (strstr(message, buf)) // "I am %s Super Novice~" + sd->state.snovice_call_flag = 2; + } + break; + case 2: + if (strstr(message, msg_txt(1481))) // "Help me out~ Please~ T_T" + sd->state.snovice_call_flag = 3; + break; + case 3: + sc_start(NULL, &sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] + clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions + sd->state.snovice_call_flag = 0; + break; + } + } +} + void do_final_pc(void) { db_destroy(pc->itemcd_db); pc->at_db->destroy(pc->at_db,pc->autotrade_final); @@ -11785,7 +12206,8 @@ void pc_defaults(void) { pc->addspiritball = pc_addspiritball; pc->delspiritball = pc_delspiritball; pc->addfame = pc_addfame; - pc->famerank = pc_famerank; + pc->fame_rank = pc_fame_rank; + pc->famelist_type = pc_famelist_type; pc->set_hate_mob = pc_set_hate_mob; pc->getmaxspiritball = pc_getmaxspiritball; @@ -11857,6 +12279,9 @@ void pc_defaults(void) { pc->db_checkid = pc_db_checkid; pc->validate_levels = pc_validate_levels; + pc->check_supernovice_call = pc_check_supernovice_call; + pc->process_chat_message = pc_process_chat_message; + /** * Autotrade persistency [Ind/Hercules <3] **/ @@ -11869,6 +12294,8 @@ void pc_defaults(void) { pc->check_job_name = pc_check_job_name; pc->update_idle_time = pc_update_idle_time; - + pc->have_magnifier = pc_have_magnifier; + + pc->check_basicskill = pc_check_basicskill; } |