diff options
Diffstat (limited to 'src/map/pc.c')
-rw-r--r-- | src/map/pc.c | 257 |
1 files changed, 165 insertions, 92 deletions
diff --git a/src/map/pc.c b/src/map/pc.c index 848238ed2..8b84ee3bc 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2,20 +2,16 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/core.h" // get_svn_revision() -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/socket.h" // session[] -#include "../common/strlib.h" // safestrncpy() -#include "../common/timer.h" -#include "../common/utils.h" -#include "../common/conf.h" -#include "../common/mmo.h" //NAME_LENGTH +#define HERCULES_CORE +#include "../config/core.h" // DBPATH, GP_BOUND_ITEMS, MAX_SPIRITBALL, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EXP, SECURE_NPCTIMEOUT #include "pc.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config #include "battleground.h" @@ -24,32 +20,40 @@ #include "clif.h" #include "date.h" // is_day_of_*() #include "duel.h" +#include "elemental.h" +#include "guild.h" // guild->search(), guild_request_info() +#include "homunculus.h" +#include "instance.h" #include "intif.h" #include "itemdb.h" #include "log.h" #include "mail.h" #include "map.h" -#include "path.h" -#include "homunculus.h" -#include "instance.h" #include "mercenary.h" -#include "elemental.h" +#include "mob.h" // struct mob_data #include "npc.h" // fake_nd -#include "pet.h" // pet_unlocktarget() #include "party.h" // party->search() -#include "guild.h" // guild->search(), guild_request_info() +#include "path.h" +#include "pc_groups.h" +#include "pet.h" // pet_unlocktarget() +#include "quest.h" #include "script.h" // script_config #include "skill.h" #include "status.h" // struct status_data #include "storage.h" -#include "pc_groups.h" -#include "quest.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/core.h" // get_svn_revision() +#include "../common/malloc.h" +#include "../common/mmo.h" // NAME_LENGTH, MAX_CARTS, NEW_CARTS +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" // session[] +#include "../common/strlib.h" // safestrncpy() +#include "../common/sysinfo.h" +#include "../common/timer.h" +#include "../common/utils.h" struct pc_interface pc_s; @@ -1147,19 +1151,12 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim if( !changing_mapservers ) { if (battle_config.display_version == 1) { - const char* svn = get_svn_revision(); - const char* git = get_git_hash(); char buf[256]; - if( git[0] != HERC_UNKNOWN_VER ) - sprintf(buf,"Git Hash: %s", git); - else if( svn[0] != HERC_UNKNOWN_VER ) - sprintf(buf,"SVN Revision: %s", svn); - else - sprintf(buf,"Unknown Version"); + sprintf(buf, msg_txt(1295), sysinfo->vcstype(), sysinfo->vcsrevision_src(), sysinfo->vcsrevision_scripts()); // %s revision '%s' (src) / '%s' (scripts) clif->message(sd->fd, buf); } - if (expiration_time != 0) { + if (expiration_time != 0) { sd->expiration_time = expiration_time; } @@ -1394,7 +1391,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) { switch( skill->db[i].nameid ) { case NV_TRICKDEAD: - if( (sd->class_&MAPID_BASEMASK) != MAPID_NOVICE ) { + 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; @@ -3998,10 +3995,10 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l sd->inventory_data[i] = data; clif->additem(sd,i,amount,0); } -#ifdef NSI_UNIQUE_ID + if( !itemdb->isstackable2(data) && !item_data->unique_id ) - sd->status.inventory[i].unique_id = itemdb->unique_id(0,0); -#endif + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); + logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]); sd->weight += w; @@ -4194,7 +4191,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( !item->script ) //if it has no script, you can't really consume it! return 0; - if( (item->item_usage.flag&NOUSE_SITTING) && (pc_issit(sd) == 1) && (pc_get_group_level(sd) < item->item_usage.override) ) { + if( (item->item_usage.flag&INR_SITTING) && (pc_issit(sd) == 1) && (pc_get_group_level(sd) < item->item_usage.override) ) { clif->msgtable(sd->fd,0x297); //clif->colormes(sd->fd,COLOR_WHITE,msg_txt(1474)); return 0; // You cannot use this item while sitting. @@ -4387,6 +4384,7 @@ int pc_useitem(struct map_session_data *sd,int n) { if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING) return 0; + // Statuses that don't let the player use items if (sd->sc.count && ( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) || @@ -4399,6 +4397,7 @@ int pc_useitem(struct map_session_data *sd,int n) { sd->sc.data[SC_WHITEIMPRISON] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || + sd->sc.data[SC_COLD] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) )) return 0; @@ -4451,7 +4450,7 @@ int pc_useitem(struct map_session_data *sd,int n) { } } - /* on restricted maps the item is consumed but the effect is not used */ + /* on restricted maps the item is consumed but the effect is not used */ for(i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++) { if( map->list[sd->bl.m].zone->disabled_items[i] == nameid ) { clif->msg(sd, ITEM_CANT_USE_AREA); // This item cannot be used within this area @@ -5944,9 +5943,9 @@ int pc_checkjoblevelup(struct map_session_data *sd) return 1; } -/*========================================== - * Alters experienced based on self bonuses that do not get even shared to the party. - *------------------------------------------*/ +/** + * 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); @@ -5977,19 +5976,23 @@ void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned in return; } -/*========================================== - * Give x exp at sd player and calculate remaining exp for next lvl - *------------------------------------------*/ -int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int base_exp,unsigned int job_exp,bool is_quest) { + +/** + * Gives a determined EXP amount to sd and calculates remaining EXP for next level + * @param src if is NULL no bonuses are taken into account + * @param is_quest Used to let client know that the EXP was from a quest (clif->displayexp) PACKETVER >= 20091027 + * @retval true success + **/ +bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int base_exp,unsigned int job_exp,bool is_quest) { float nextbp=0, nextjp=0; unsigned int nextb=0, nextj=0; nullpo_ret(sd); if(sd->bl.prev == NULL || pc_isdead(sd)) - return 0; + return false; if(!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] - return 0; // no exp on pvp maps + return false; // no exp on pvp maps if(sd->status.guild_id>0) base_exp-=guild->payexp(sd,base_exp); @@ -6021,7 +6024,8 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int } } - //Cap exp to the level up requirement of the previous level when you are at max level, otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex] + // Cap exp to the level up requirement of the previous level when you are at max level, + // otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex] if (base_exp) { nextb = nextb?UINT_MAX:pc->thisbaseexp(sd); if(sd->status.base_exp > nextb - base_exp) @@ -6056,7 +6060,7 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int clif_disp_onlyself(sd,output,strlen(output)); } - return 1; + return true; } /*========================================== @@ -6231,7 +6235,7 @@ int pc_maxparameterincrease(struct map_session_data* sd, int type) { * Subtracts status points according to the cost of the increased stat points. * * @param sd The target character. - * @param type The stat to change (see enum _sp) + * @param type The stat to change (see enum status_point_types) * @param increase The stat increase (strictly positive) amount. * @retval true if the stat was increased by any amount. * @retval false if there were no changes. @@ -6290,7 +6294,7 @@ bool pc_statusup(struct map_session_data* sd, int type, int increase) { * Does not subtract status points for the cost of the modified stat points. * * @param sd The target character. - * @param type The stat to change (see enum _sp) + * @param type The stat to change (see enum status_point_types) * @param val The stat increase (or decrease) amount. * @return the stat increase amount. * @retval 0 if no changes were made. @@ -6613,7 +6617,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex] clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1); 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) ) i &= ~OPTION_RIDING; if( i&OPTION_FALCON && pc->checkskill(sd, HT_FALCON) ) i &= ~OPTION_FALCON; @@ -6652,14 +6656,14 @@ int pc_resetskill(struct map_session_data* sd, int flag) skill_id = skill->db[i].nameid; // Don't reset trick dead if not a novice/baby - if( skill_id == NV_TRICKDEAD && (sd->class_&MAPID_BASEMASK) != MAPID_NOVICE ) { + if( skill_id == NV_TRICKDEAD && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != 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) != MAPID_NOVICE ) + if( skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) continue; if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) @@ -6691,6 +6695,21 @@ int pc_resetskill(struct map_session_data* sd, int flag) sd->status.skill_point += skill_point; + + if( !(flag&2) ) { + // Remove all SCs that can't be inactivated without a skill + if( sd->sc.data[SC_STORMKICK_READY] ) + status_change_end(&sd->bl, SC_STORMKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_DOWNKICK_READY] ) + status_change_end(&sd->bl, SC_DOWNKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_TURNKICK_READY] ) + status_change_end(&sd->bl, SC_TURNKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_COUNTERKICK_READY] ) + status_change_end(&sd->bl, SC_COUNTERKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_DODGE_READY] ) + status_change_end(&sd->bl, SC_DODGE_READY, INVALID_TIMER); + } + if( flag&1 ) { clif->updatestatus(sd,SP_SKILLPOINT); clif->skillinfoblock(sd); @@ -6839,13 +6858,14 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { int i=0,j=0; int64 tick = timer->gettick(); - for(j = 0; j < 5; j++) + for(j = 0; j < 5; j++) { if (sd->devotion[j]){ struct map_session_data *devsd = map->id2sd(sd->devotion[j]); if (devsd) status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER); sd->devotion[j] = 0; } + } if(sd->status.pet_id > 0 && sd->pd) { struct pet_data *pd = sd->pd; @@ -6860,7 +6880,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } if (sd->status.hom_id > 0){ - if(battle_config.homunculus_auto_vapor && sd->hd && !sd->hd->sc.data[SC_LIGHT_OF_REGENE]) + if(battle_config.homunculus_auto_vapor && sd->hd) homun->vaporize(sd, HOM_ST_REST); } @@ -7143,6 +7163,17 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } } } + + // Remove autotrade to prevent autotrading from save point + if( (sd->state.standalone || sd->state.autotrade) + && (map->list[sd->bl.m].flag.pvp || map->list[sd->bl.m].flag.gvg) + ) { + sd->state.autotrade = 0; + sd->state.standalone = 0; + pc->autotrade_update(sd,PAUC_REMOVE); + map->quit(sd); + } + // pvp // disable certain pvp functions on pk_mode [Valaris] if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) { @@ -7172,10 +7203,10 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } } - //Reset "can log out" tick. if( battle_config.prevent_logout ) sd->canlog_tick = timer->gettick() - battle_config.prevent_logout; + return 1; } @@ -7255,7 +7286,7 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_DEFELE: val = sd->battle_status.def_ele; break; #ifndef RENEWAL_CAST case SP_VARCASTRATE: -#endif +#endif case SP_CASTRATE: val = sd->castrate+=val; break; @@ -7973,22 +8004,21 @@ int pc_setoption(struct map_session_data *sd,int type) else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_FALCON); - if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) { - if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting - clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0); - status_calc_pc(sd,SCO_NONE); - } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount - clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER); - status_calc_pc(sd,SCO_NONE); - } + if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting + clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0); + status_calc_pc(sd,SCO_NONE); + } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount + clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER); + status_calc_pc(sd,SCO_NONE); } - if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) { + + if( (type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR)) + || (!(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR) ) { int i; - if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) - status_calc_pc(sd, SCO_NONE); - else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) - status_calc_pc(sd, SCO_NONE); - for( i = 0; i < SC_MAX; i++ ){ + status_calc_pc(sd, SCO_NONE); + + // End all SCs that can be reset when mado is taken off + for( i = 0; i < SC_MAX; i++ ) { if ( !sd->sc.data[i] || !status->get_sc_type(i) ) continue; if ( status->get_sc_type(i)&SC_MADO_NO_RESET ) @@ -8030,7 +8060,7 @@ int pc_setoption(struct map_session_data *sd,int type) *------------------------------------------*/ int pc_setcart(struct map_session_data *sd,int type) { #ifndef NEW_CARTS - int cart[6] = {0x0000,OPTION_CART1,OPTION_CART2,OPTION_CART3,OPTION_CART4,OPTION_CART5}; + int cart[6] = {OPTION_NOTHING,OPTION_CART1,OPTION_CART2,OPTION_CART3,OPTION_CART4,OPTION_CART5}; int option; #endif nullpo_ret(sd); @@ -8108,19 +8138,62 @@ int pc_setriding(TBL_PC* sd, int flag) return 0; } -/*========================================== - * Give player a mado - *------------------------------------------*/ -int pc_setmadogear(TBL_PC* sd, int flag) -{ - if( flag ){ - if( pc->checkskill(sd,NC_MADOLICENCE) > 0 ) +/** + * Gives player a mado + * @param flag 1 Set mado + **/ +void pc_setmadogear( struct map_session_data *sd, int flag ) { + if( flag ) { + if( (sd->class_&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); - } + } else if( pc_ismadogear(sd) ) + pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR); - return 0; + return; +} + +/** + * Determines whether a player can attack based on status changes + * Why not use status_check_skilluse? + * "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack." + * Even ground-based attacks should be blocked by these statuses + * Called from unit_attack and unit_attack_timer_sub + * @retval true Can attack + **/ +bool pc_can_attack( struct map_session_data *sd, int target_id ) { + nullpo_retr(false, sd); + + if( sd->sc.data[SC_BASILICA] || + sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__MANHOLE] || + sd->sc.data[SC_CURSEDCIRCLE_ATKER] || + sd->sc.data[SC_CURSEDCIRCLE_TARGET] || + sd->sc.data[SC_COLD] || + sd->sc.data[SC_ALL_RIDING] || // The client doesn't let you, this is to make cheat-safe + sd->sc.data[SC_TRICKDEAD] || + (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) || + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] || + sd->sc.data[SC_FALLENEMPIRE] ) + return false; + + return true; +} + +/** + * Determines whether a player can talk/whisper based on status changes + * Called from clif_parse_GlobalMessage and clif_parse_WisMessage + * @retval true Can talk + **/ +bool pc_can_talk( struct map_session_data *sd ) { + nullpo_retr(false, sd); + + if( sd->sc.data[SC_BERSERK] || + (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || + (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + return false; + + return true; } /*========================================== @@ -9936,7 +10009,7 @@ void pc_read_skill_tree(void) { if( a == MAX_SKILL_TREE ) { ShowWarning("pc_read_skill_tree: '%s' can't inherit '%s', skill tree is full!\n", name,iname); break; - } else if ( pc->skill_tree[idx][a].id || ( pc->skill_tree[idx][a].id == NV_TRICKDEAD && ((pc->jobid2mapid(jnames[k].id)&MAPID_BASEMASK)!=MAPID_NOVICE) ) ) /* we skip trickdead for non-novices */ + } else if ( pc->skill_tree[idx][a].id || ( pc->skill_tree[idx][a].id == NV_TRICKDEAD && ((pc->jobid2mapid(jnames[k].id)&(MAPID_BASEMASK|JOBL_2))!=MAPID_NOVICE) ) ) /* we skip trickdead for non-novices */ continue;/* skip */ memcpy(&pc->skill_tree[idx][a],&pc->skill_tree[fidx][f],sizeof(pc->skill_tree[fidx][f])); @@ -10320,7 +10393,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) { +void pc_expire_check(struct map_session_data *sd) { /* ongoing timer */ if( sd->expiration_tid != INVALID_TIMER ) return; @@ -10621,7 +10694,7 @@ void do_init_pc(bool minimal) { ers_chunk_size(pc->str_reg_ers, 50); } /*===================================== -* Default Functions : pc.h +* Default Functions : pc.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ @@ -10645,9 +10718,7 @@ void pc_defaults(void) { memset(pc->exp_table, 0, sizeof(pc->exp_table) + sizeof(pc->max_level) + sizeof(pc->statp) -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) + sizeof(pc->level_penalty) -#endif + sizeof(pc->skill_tree) + sizeof(pc->smith_fame_list) + sizeof(pc->chemist_fame_list) @@ -10829,6 +10900,8 @@ void pc_defaults(void) { pc->setstand = pc_setstand; pc->candrop = pc_candrop; + pc->can_talk = pc_can_talk; + pc->can_attack = pc_can_attack; pc->jobid2mapid = pc_jobid2mapid; // Skotlex pc->mapid2jobid = pc_mapid2jobid; // Skotlex |