diff options
Diffstat (limited to 'src/map/pc.c')
-rw-r--r-- | src/map/pc.c | 349 |
1 files changed, 288 insertions, 61 deletions
diff --git a/src/map/pc.c b/src/map/pc.c index 57b2fe19a..2206dbb80 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -81,8 +81,10 @@ struct pc_interface *pc; //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; + if (class_ >= JOB_NOVICE_HIGH) { + class_ += - JOB_NOVICE_HIGH + JOB_MAX_BASIC; + } + Assert_ret(class_ >= 0 && class_ < CLASS_COUNT); return class_; } @@ -109,6 +111,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; @@ -121,6 +124,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); } @@ -141,7 +145,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; @@ -466,6 +471,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); @@ -476,7 +482,11 @@ 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 ) { @@ -547,6 +557,7 @@ 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 ) @@ -686,6 +697,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; @@ -812,6 +824,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; @@ -891,6 +904,7 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd, 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; @@ -1039,7 +1053,10 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim { 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; @@ -1269,6 +1286,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; } @@ -1306,6 +1324,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")); @@ -1632,6 +1651,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?? @@ -1697,6 +1717,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; @@ -1714,8 +1735,10 @@ 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_; + int c; + nullpo_ret(sd); + c = sd->class_; if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) return c; @@ -1822,6 +1845,7 @@ int pc_updateweightstatus(struct map_session_data *sd) } 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_) @@ -1864,8 +1888,8 @@ int pc_disguise(struct map_session_data *sd, int class_) { 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); @@ -1881,6 +1905,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 ) @@ -1917,6 +1943,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 @@ -1952,6 +1980,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))) @@ -1981,6 +2011,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; @@ -2001,6 +2033,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) @@ -2048,6 +2081,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 ) { @@ -2084,6 +2119,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++ ) { @@ -2155,6 +2191,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); @@ -2188,6 +2225,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) @@ -4093,7 +4131,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; } /** @@ -4113,7 +4151,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; } /*========================================== @@ -4276,7 +4314,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; @@ -4318,7 +4356,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; } @@ -4343,7 +4381,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; } @@ -4366,7 +4404,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; } @@ -4404,7 +4442,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; @@ -4563,6 +4601,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; @@ -4706,6 +4745,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; @@ -4892,6 +4932,7 @@ 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 */ @@ -5112,6 +5153,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; @@ -5170,6 +5212,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 ) @@ -5204,9 +5247,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: @@ -5341,7 +5387,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil 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); + intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT); } return 1; } @@ -6440,6 +6486,7 @@ int pc_check_job_name(const char *name) { { "Rebellion", JOB_REBELLION }, }; + nullpo_retr(-1, name); len = ARRAYLENGTH(names); ARR_FIND(0, len, i, strcmpi(names[i].name, name) == 0); @@ -6506,6 +6553,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) @@ -6520,6 +6568,7 @@ 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; @@ -6569,6 +6618,7 @@ 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 ) @@ -6613,34 +6663,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); - 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] + jexp = *job_exp; + bexp = *base_exp; - 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; + 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 + + //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]; + } - *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 && (int)(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); } /** @@ -6654,24 +6742,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) @@ -6726,7 +6815,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; @@ -7875,6 +7964,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); @@ -8210,6 +8300,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); @@ -8233,6 +8324,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) @@ -8803,6 +8895,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); @@ -8821,6 +8914,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); @@ -8839,6 +8933,7 @@ 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) pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR); @@ -8857,6 +8952,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) @@ -8889,6 +8985,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); @@ -8956,6 +9053,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); } /** @@ -8964,6 +9062,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 ) @@ -8981,6 +9080,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; @@ -8993,6 +9093,8 @@ void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { unsigned int index = script_getvaridx(reg); struct DBData prev; + nullpo_retv(sd); + nullpo_retv(str); if( str[0] ) { p = ers_alloc(pc->str_reg_ers, struct script_reg_str); @@ -9028,6 +9130,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. @@ -9049,6 +9152,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. @@ -9072,6 +9176,7 @@ 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 @@ -9147,6 +9252,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; @@ -9224,6 +9331,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 ) @@ -9244,6 +9352,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; @@ -9312,6 +9421,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 */ @@ -9387,6 +9498,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 */ @@ -9431,6 +9544,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]; @@ -9463,6 +9577,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) @@ -9574,7 +9689,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) if(battle_config.battle_log) 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==1 ) { // [Valaris] + 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; @@ -9693,6 +9808,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; @@ -10048,6 +10164,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; @@ -10202,6 +10319,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; @@ -10235,6 +10353,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) { @@ -10312,6 +10431,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; @@ -10335,7 +10455,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; } @@ -10355,7 +10475,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; } @@ -10376,6 +10496,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 @@ -10401,6 +10522,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; @@ -10589,6 +10711,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,','); @@ -10601,6 +10724,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); @@ -10618,6 +10742,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; @@ -10870,6 +10995,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]); @@ -11014,18 +11140,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]); @@ -11037,8 +11163,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 @@ -11046,7 +11172,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++; @@ -11112,6 +11239,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 @@ -11143,7 +11271,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); @@ -11163,8 +11294,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; @@ -11188,6 +11321,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); @@ -11195,7 +11329,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); } @@ -11236,6 +11370,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; @@ -11293,6 +11428,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); @@ -11337,6 +11473,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)) @@ -11390,6 +11527,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)); @@ -11436,6 +11574,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; @@ -11478,6 +11617,7 @@ void pc_autotrade_populate(struct map_session_data *sd) { 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; } @@ -11516,6 +11656,90 @@ int pc_have_magnifier(struct map_session_data *sd) return n; } +/** + * 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->class_&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); @@ -11871,6 +12095,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] **/ @@ -11883,6 +12110,6 @@ 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; } |