diff options
author | Happy <markaizer@gmail.com> | 2014-08-21 04:50:46 +0800 |
---|---|---|
committer | Happy <markaizer@gmail.com> | 2014-08-21 04:50:46 +0800 |
commit | f52e1007fe08c67003c0bc4c78231904dd3fd5cc (patch) | |
tree | 99907d827264e501774e58ab4630e41fa7103c02 /src/map/pc.c | |
parent | 2410110dece79b4598c12f1c953219f1d0d1904a (diff) | |
parent | 769b1d05aa5cfa8cddfe7d21b35d5c5e4da3bbd6 (diff) | |
download | hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.gz hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.bz2 hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.tar.xz hercules-f52e1007fe08c67003c0bc4c78231904dd3fd5cc.zip |
Merge pull request #1 from HerculesWS/master
Update from original
Diffstat (limited to 'src/map/pc.c')
-rw-r--r-- | src/map/pc.c | 5753 |
1 files changed, 3354 insertions, 2399 deletions
diff --git a/src/map/pc.c b/src/map/pc.c index b7644f2fb..a6619fad2 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2,90 +2,60 @@ // 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/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" +#include "chat.h" #include "chrif.h" #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 "pc.h" -#include "pc_groups.h" -#include "quest.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - - -#define PVP_CALCRANK_INTERVAL 1000 // PVP calculation interval -static unsigned int exp_table[CLASS_COUNT][2][MAX_LEVEL]; -static unsigned int max_level[CLASS_COUNT][2]; -static unsigned int statp[MAX_LEVEL+1]; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static unsigned int level_penalty[3][RC_MAX][MAX_LEVEL*2+1]; -#endif - -// h-files are for declarations, not for implementations... [Shinomori] -struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; -// timer for night.day implementation -int day_timer_tid; -int night_timer_tid; - -struct fame_list smith_fame_list[MAX_FAME_LIST]; -struct fame_list chemist_fame_list[MAX_FAME_LIST]; -struct fame_list taekwon_fame_list[MAX_FAME_LIST]; - -static unsigned short equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO}; - -//Links related info to the sd->hate_mob[]/sd->feel_map[] entries -const struct sg_data sg_info[MAX_PC_FEELHATE] = { - { SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun }, - { SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon }, - { SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star } - }; +#include "storage.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" -/** - * Item Cool Down Delay Saving - * Struct item_cd is not a member of struct map_session_data - * to keep cooldowns in memory between player log-ins. - * All cooldowns are reset when server is restarted. - **/ -DBMap* itemcd_db = NULL; // char_id -> struct skill_cd -struct item_cd { - unsigned int tick[MAX_ITEMDELAYS];//tick - short nameid[MAX_ITEMDELAYS];//skill id -}; +struct pc_interface pc_s; //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 @@ -96,15 +66,48 @@ int pc_class2idx(int class_) { return class_; } -int pc_get_group_level(struct map_session_data *sd) { - return sd->group_level; +/** + * Creates a new dummy map session data. + * Used when there is no real player attached, but it is + * required to provide a session. + * Caller must release dummy on its own when it's no longer needed. + */ +struct map_session_data* pc_get_dummy_sd(void) +{ + struct map_session_data *dummy_sd; + CREATE(dummy_sd, struct map_session_data, 1); + dummy_sd->group = pcg->get_dummy_group(); // map_session_data.group is expected to be non-NULL at all times + return dummy_sd; } -static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data) +/** + * Sets player's group. + * Caller should handle error (preferably display message and disconnect). + * @param group_id Group ID + * @return 1 on error, 0 on success + */ +int pc_set_group(struct map_session_data *sd, int group_id) { + GroupSettings *group = pcg->id2group(group_id); + if (group == NULL) + return 1; + sd->group_id = group_id; + sd->group = group; + return 0; +} + +/** + * Checks if commands used by player should be logged. + */ +bool pc_should_log_commands(struct map_session_data *sd) +{ + return pcg->should_log_commands(sd->group); +} + +int pc_invincible_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; if(sd->invincible_timer != tid){ @@ -120,11 +123,11 @@ static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data void pc_setinvincibletimer(struct map_session_data* sd, int val) { nullpo_retv(sd); - val += map[sd->bl.m].invincible_time_inc; + val += map->list[sd->bl.m].invincible_time_inc; if( sd->invincible_timer != INVALID_TIMER ) - iTimer->delete_timer(sd->invincible_timer,pc_invincible_timer); - sd->invincible_timer = iTimer->add_timer(iTimer->gettick()+val,pc_invincible_timer,sd->bl.id,0); + timer->delete(sd->invincible_timer,pc->invincible_timer); + sd->invincible_timer = timer->add(timer->gettick()+val,pc->invincible_timer,sd->bl.id,0); } void pc_delinvincibletimer(struct map_session_data* sd) @@ -133,18 +136,17 @@ void pc_delinvincibletimer(struct map_session_data* sd) if( sd->invincible_timer != INVALID_TIMER ) { - iTimer->delete_timer(sd->invincible_timer,pc_invincible_timer); + timer->delete(sd->invincible_timer,pc->invincible_timer); sd->invincible_timer = INVALID_TIMER; - skill->unit_move(&sd->bl,iTimer->gettick(),1); + skill->unit_move(&sd->bl,timer->gettick(),1); } } -static int pc_spiritball_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_spiritball_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; int i; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; if( sd->spiritball <= 0 ) @@ -184,21 +186,21 @@ int pc_addspiritball(struct map_session_data *sd,int interval,int max) if( sd->spiritball && sd->spiritball >= max ) { if(sd->spirit_timer[0] != INVALID_TIMER) - iTimer->delete_timer(sd->spirit_timer[0],pc_spiritball_timer); + timer->delete(sd->spirit_timer[0],pc->spiritball_timer); sd->spiritball--; if( sd->spiritball != 0 ) memmove(sd->spirit_timer+0, sd->spirit_timer+1, (sd->spiritball)*sizeof(int)); sd->spirit_timer[sd->spiritball] = INVALID_TIMER; } - tid = iTimer->add_timer(iTimer->gettick()+interval, pc_spiritball_timer, sd->bl.id, 0); - ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick, iTimer->get_timer(sd->spirit_timer[i])->tick) < 0); + tid = timer->add(timer->gettick()+interval, pc->spiritball_timer, sd->bl.id, 0); + ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->spirit_timer[i])->tick) < 0); if( i != sd->spiritball ) 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 ) - clif->millenniumshield(sd,sd->spiritball); + clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); @@ -226,7 +228,7 @@ int pc_delspiritball(struct map_session_data *sd,int count,int type) for(i=0;i<count;i++) { if(sd->spirit_timer[i] != INVALID_TIMER) { - iTimer->delete_timer(sd->spirit_timer[i],pc_spiritball_timer); + timer->delete(sd->spirit_timer[i],pc->spiritball_timer); sd->spirit_timer[i] = INVALID_TIMER; } } @@ -237,13 +239,13 @@ int pc_delspiritball(struct map_session_data *sd,int count,int type) if(!type) { if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD ) - clif->millenniumshield(sd,sd->spiritball); + clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); } return 0; } -static int pc_check_banding( struct block_list *bl, va_list ap ) { +int pc_check_banding( struct block_list *bl, va_list ap ) { int *c, *b_sd; struct block_list *src; struct map_session_data *tsd; @@ -258,7 +260,7 @@ static int pc_check_banding( struct block_list *bl, va_list ap ) { if(pc_isdead(tsd)) return 0; - sc = status_get_sc(bl); + sc = status->get_sc(bl); if( bl == src ) return 0; @@ -283,14 +285,14 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { c = 0; memset(b_sd, 0, sizeof(b_sd)); - i = party_foreachsamemap(pc_check_banding,sd,range,&sd->bl,&c,&b_sd); + i = party->foreachsamemap(pc->check_banding,sd,range,&sd->bl,&c,&b_sd); - if( c < 1 ) //just recalc status no need to recalc hp - { // No more Royal Guards in Banding found. - if( (sc = status_get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) - { + if( c < 1 ) { + //just recalc status no need to recalc hp + if( (sc = status->get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) { + // No more Royal Guards in Banding found. sc->data[SC_BANDING]->val2 = 0; // Reset the counter - status_calc_bl(&sd->bl, status_sc2scb_flag(SC_BANDING)); + status_calc_bl(&sd->bl, status->sc2scb_flag(SC_BANDING)); } return 0; } @@ -300,9 +302,8 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { i++; // Get total HP of all Royal Guards in party. - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); if( bsd != NULL ) hp += status_get_hp(&bsd->bl); } @@ -311,9 +312,8 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { hp = hp / i; // If a Royal Guard have full HP, give more HP to others that haven't full HP. - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); if( bsd != NULL && (tmp_hp = hp - status_get_max_hp(&bsd->bl)) > 0 ) { extra_hp += tmp_hp; @@ -324,16 +324,13 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { if( extra_hp > 0 && tmp_qty > 0 ) hp += extra_hp / tmp_qty; - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); - if( bsd != NULL ) - { - status_set_hp(&bsd->bl,hp,0); // Set hp - if( (sc = status_get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) - { + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); + if( bsd != NULL ) { + status->set_hp(&bsd->bl,hp,0); // Set hp + if( (sc = status->get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) { sc->data[SC_BANDING]->val2 = c; // Set the counter. It doesn't count your self. - status_calc_bl(&bsd->bl, status_sc2scb_flag(SC_BANDING)); // Set atk and def. + status_calc_bl(&bsd->bl, status->sc2scb_flag(SC_BANDING)); // Set atk and def. } } } @@ -344,22 +341,18 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { // Increases a player's fame points and displays a notice to him void pc_addfame(struct map_session_data *sd,int count) { + int ranktype = -1; nullpo_retv(sd); sd->status.fame += count; if(sd->status.fame > MAX_FAME) sd->status.fame = MAX_FAME; switch(sd->class_&MAPID_UPPERMASK){ - case MAPID_BLACKSMITH: // Blacksmith - clif->fame_blacksmith(sd,count); - break; - case MAPID_ALCHEMIST: // Alchemist - clif->fame_alchemist(sd,count); - break; - case MAPID_TAEKWON: // Taekwon - clif->fame_taekwon(sd,count); - break; + case MAPID_BLACKSMITH: ranktype = RANKTYPE_BLACKSMITH; break; + case MAPID_ALCHEMIST: ranktype = RANKTYPE_ALCHEMIST; break; + case MAPID_TAEKWON: ranktype = RANKTYPE_TAEKWON; break; } - chrif_updatefamelist(sd); + 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 @@ -370,19 +363,19 @@ unsigned char pc_famerank(int char_id, int job) switch(job){ case MAPID_BLACKSMITH: // Blacksmith for(i = 0; i < MAX_FAME_LIST; i++){ - if(smith_fame_list[i].id == char_id) + 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(chemist_fame_list[i].id == char_id) + 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(taekwon_fame_list[i].id == char_id) + if(pc->taekwon_fame_list[i].id == char_id) return i + 1; } break; @@ -392,20 +385,20 @@ unsigned char pc_famerank(int char_id, int job) } int pc_setrestartvalue(struct map_session_data *sd,int type) { - struct status_data *status, *b_status; + struct status_data *st, *bst; nullpo_ret(sd); - b_status = &sd->base_status; - status = &sd->battle_status; + bst = &sd->base_status; + st = &sd->battle_status; if (type&1) { //Normal resurrection - status->hp = 1; //Otherwise status_heal may fail if dead. - status_heal(&sd->bl, b_status->hp, 0, 1); - if( status->sp < b_status->sp ) - status_set_sp(&sd->bl, b_status->sp, 1); + st->hp = 1; //Otherwise status->heal may fail if dead. + status->heal(&sd->bl, bst->hp, 0, 1); + if( st->sp < bst->sp ) + status->set_sp(&sd->bl, bst->sp, 1); } else { //Just for saving on the char-server (with values as if respawned) - sd->status.hp = b_status->hp; - sd->status.sp = (status->sp < b_status->sp)?b_status->sp:status->sp; + sd->status.hp = bst->hp; + sd->status.sp = (st->sp < bst->sp) ? bst->sp : st->sp; } return 0; } @@ -413,9 +406,8 @@ int pc_setrestartvalue(struct map_session_data *sd,int type) { /*========================================== Rental System *------------------------------------------*/ -static int pc_inventory_rental_end(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_inventory_rental_end(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); if( sd == NULL ) return 0; if( tid != sd->rental_timer ) @@ -432,17 +424,84 @@ int pc_inventory_rental_clear(struct map_session_data *sd) { if( sd->rental_timer != INVALID_TIMER ) { - iTimer->delete_timer(sd->rental_timer, pc_inventory_rental_end); + timer->delete(sd->rental_timer, pc->inventory_rental_end); sd->rental_timer = INVALID_TIMER; } return 1; } +/* 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; + /* Soon to be dropped, we got plans to integrate it with item db */ + switch( nameid ) { + case ITEMID_REINS_OF_MOUNT: + status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); + break; + case ITEMID_LOVE_ANGEL: + if( sd->status.font == 1 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_SQUIRREL: + if( sd->status.font == 2 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_GOGO: + if( sd->status.font == 3 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_PICTURE_DIARY: + if( sd->status.font == 4 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MINI_HEART: + if( sd->status.font == 5 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_NEWCOMER: + if( sd->status.font == 6 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_KID: + if( sd->status.font == 7 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MAGIC_CASTLE: + if( sd->status.font == 8 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_BULGING_HEAD: + if( sd->status.font == 9 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + } + + clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); +} void pc_inventory_rentals(struct map_session_data *sd) { int i, c = 0; - unsigned int expire_tick, next_tick = UINT_MAX; + int64 expire_tick, next_tick = INT64_MAX; for( i = 0; i < MAX_INVENTORY; i++ ) { // Check for Rentals on Inventory @@ -452,14 +511,9 @@ void pc_inventory_rentals(struct map_session_data *sd) continue; if( sd->status.inventory[i].expire_time <= time(NULL) ) { - if( sd->status.inventory[i].nameid == ITEMID_REINS_OF_MOUNT - && sd->sc.data[SC_ALL_RIDING] ) { - status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); - } - clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); + pc->rental_expire(sd,i); } else { - expire_tick = (unsigned int)(sd->status.inventory[i].expire_time - time(NULL)) * 1000; + expire_tick = (int64)(sd->status.inventory[i].expire_time - time(NULL)) * 1000; clif->rental_time(sd->fd, sd->status.inventory[i].nameid, (int)(expire_tick / 1000)); next_tick = min(expire_tick, next_tick); c++; @@ -467,7 +521,7 @@ void pc_inventory_rentals(struct map_session_data *sd) } if( c > 0 ) // min(next_tick,3600000) 1 hour each timer to keep announcing to the owner, and to avoid a but with rental time > 15 days - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + min(next_tick,3600000), pc_inventory_rental_end, sd->bl.id, 0); + sd->rental_timer = timer->add(timer->gettick() + min(next_tick,3600000), pc->inventory_rental_end, sd->bl.id, 0); else sd->rental_timer = INVALID_TIMER; } @@ -482,23 +536,15 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds) if( sd->rental_timer != INVALID_TIMER ) { const struct TimerData * td; - td = iTimer->get_timer(sd->rental_timer); - if( DIFF_TICK(td->tick, iTimer->gettick()) > tick ) + td = timer->get(sd->rental_timer); + if( DIFF_TICK(td->tick, timer->gettick()) > tick ) { // Update Timer as this one ends first than the current one pc->inventory_rental_clear(sd); - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + tick, pc_inventory_rental_end, sd->bl.id, 0); + sd->rental_timer = timer->add(timer->gettick() + tick, pc->inventory_rental_end, sd->bl.id, 0); } } else - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + min(tick,3600000), pc_inventory_rental_end, sd->bl.id, 0); -} - -/** - * Determines if player can give / drop / trade / vend items - */ -bool pc_can_give_items(struct map_session_data *sd) -{ - return pc_has_permission(sd, PC_PERM_TRADE); + sd->rental_timer = timer->add(timer->gettick() + min(tick,3600000), pc->inventory_rental_end, sd->bl.id, 0); } /*========================================== @@ -542,8 +588,8 @@ int pc_makesavestatus(struct map_session_data *sd) sd->status.last_point.y = sd->bl.y; } - if(map[sd->bl.m].flag.nosave || map[sd->bl.m].instance_id >= 0){ - struct map_data *m=&map[sd->bl.m]; + if(map->list[sd->bl.m].flag.nosave || map->list[sd->bl.m].instance_id >= 0) { + struct map_data *m=&map->list[sd->bl.m]; if(m->save.map) memcpy(&sd->status.last_point,&m->save,sizeof(sd->status.last_point)); else @@ -581,7 +627,7 @@ 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 = iTimer->gettick(); + 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; return 0; @@ -596,16 +642,21 @@ int pc_equippoint(struct map_session_data *sd,int n) if(!sd->inventory_data[n]) return 0; - if (!itemdb_isequip2(sd->inventory_data[n])) + if (!itemdb->isequip2(sd->inventory_data[n])) return 0; //Not equippable by players. ep = sd->inventory_data[n]->equip; if(sd->inventory_data[n]->look == W_DAGGER || sd->inventory_data[n]->look == W_1HSWORD || sd->inventory_data[n]->look == W_1HAXE) { - if(ep == EQP_HAND_R && (pc->checkskill(sd,AS_LEFT) > 0 || (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN || - (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech] - return EQP_ARMS; + if( (pc->checkskill(sd,AS_LEFT) > 0 || + (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN || + (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) ) { //Kagerou and Oboro can dual wield daggers. [Rytech] + if( ep == EQP_HAND_R ) + return EQP_ARMS; + if( ep == EQP_SHADOW_WEAPON ) + return EQP_SHADOW_ARMS; + } } return ep; } @@ -618,7 +669,7 @@ int pc_setinventorydata(struct map_session_data *sd) for(i=0;i<MAX_INVENTORY;i++) { id = sd->status.inventory[i].nameid; - sd->inventory_data[i] = id?itemdb_search(id):NULL; + sd->inventory_data[i] = id?itemdb->search(id):NULL; } return 0; } @@ -639,26 +690,26 @@ int pc_calcweapontype(struct map_session_data *sd) // dual-wield sd->status.weapon = 0; switch (sd->weapontype1){ - case W_DAGGER: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DD; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_DS; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_DA; break; - } - break; - case W_1HSWORD: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DS; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_SS; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_SA; break; - } - break; - case W_1HAXE: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DA; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_SA; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_AA; break; - } + case W_DAGGER: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DD; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_DS; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_DA; break; + } + break; + case W_1HSWORD: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DS; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_SS; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_SA; break; + } + break; + case W_1HAXE: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DA; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_SA; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_AA; break; + } } // unknown, default to right hand type if (!sd->status.weapon) @@ -681,7 +732,7 @@ int pc_setequipindex(struct map_session_data *sd) continue; if(sd->status.inventory[i].equip) { for(j=0;j<EQI_MAX;j++) - if(sd->status.inventory[i].equip & equip_pos[j]) + if(sd->status.inventory[i].equip & pc->equip_pos[j]) sd->equip_index[j] = i; if(sd->status.inventory[i].equip & EQP_HAND_R) @@ -701,7 +752,7 @@ int pc_setequipindex(struct map_session_data *sd) } } } - pc_calcweapontype(sd); + pc->calcweapontype(sd); return 0; } @@ -719,7 +770,7 @@ int pc_setequipindex(struct map_session_data *sd) // if( item->card[MAX_SLOTS - 1] && s < MAX_SLOTS - 1 ) // s = MAX_SLOTS - 1; // -// ARR_FIND( 0, s, i, item->card[i] && (data = itemdb_exists(item->card[i])) != NULL && data->flag.no_equip&flag ); +// ARR_FIND( 0, s, i, item->card[i] && (data = itemdb->exists(item->card[i])) != NULL && data->flag.no_equip&flag ); // return( i < s ) ? 0 : 1; //} @@ -857,12 +908,14 @@ int pc_isequip(struct map_session_data *sd,int n) if(item == NULL) return 0; - if(item->elv && sd->status.base_level < (unsigned int)item->elv) + if(item->elv && sd->status.base_level < (unsigned int)item->elv){ + clif->msg(sd, 0x6ED); return 0; -#ifdef RENEWAL - if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) + } + if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax){ + clif->msg(sd, 0x6ED); return 0; -#endif + } if(item->sex != 2 && sd->status.sex != item->sex) return 0; @@ -902,10 +955,10 @@ int pc_isequip(struct map_session_data *sd,int n) return 0; //Not usable by upper class. [Inkfish] while( 1 ) { - if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; - if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; - if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; - if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; + 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; return 0; } @@ -918,14 +971,17 @@ int pc_isequip(struct map_session_data *sd,int n) *------------------------------------------*/ 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) { int i; - unsigned long tick = iTimer->gettick(); + int64 tick = timer->gettick(); uint32 ip = session[sd->fd]->client_addr; sd->login_id2 = login_id2; - sd->group_id = group_id; - /* load user permissions */ - pc_group_pc_load(sd); + if (pc->set_group(sd, group_id) != 0) { + ShowWarning("pc_authok: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", + st->name, sd->status.account_id, group_id); + clif->authfail_fd(sd->fd, 0); + return false; + } memcpy(&sd->status, st, sizeof(*st)); @@ -965,6 +1021,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->npc_timer_id = INVALID_TIMER; sd->pvp_timer = INVALID_TIMER; sd->fontcolor_tid = INVALID_TIMER; + sd->expiration_tid = INVALID_TIMER; /** * For the Secure NPC Timeout option (check config/Secure.h) [RR] **/ @@ -985,6 +1042,8 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->cansendmail_tick = tick; sd->hchsysch_tick = tick; + sd->idletime = sockt->last_tick; + for(i = 0; i < MAX_SPIRITBALL; i++) sd->spirit_timer[i] = INVALID_TIMER; for(i = 0; i < ARRAYLENGTH(sd->autobonus); i++) @@ -1011,13 +1070,13 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim if( sd->status.option & OPTION_INVISIBLE && !pc->can_use_command(sd, "@hide") ) sd->status.option &=~ OPTION_INVISIBLE; - status_change_init(&sd->bl); + status->change_init(&sd->bl); 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_); - unit_dataset(&sd->bl); + status->set_viewdata(&sd->bl, sd->status.class_); + unit->dataset(&sd->bl); sd->guild_x = -1; sd->guild_y = -1; @@ -1037,6 +1096,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->state.dialog = 0; + sd->delayed_damage = 0; + + if( battle_config.item_check ) + sd->state.itemcheck = 1; + // Event Timers for( i = 0; i < MAX_EVENTTIMER; i++ ) sd->eventtimer[i] = INVALID_TIMER; @@ -1046,12 +1110,23 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim for( i = 0; i < 3; i++ ) sd->hate_mob[i] = -1; - //warp player + sd->quest_log = NULL; + sd->num_quests = 0; + sd->avail_quests = 0; + sd->save_quest = false; + + sd->regs.vars = i64db_alloc(DB_OPT_BASE); + sd->regs.arrays = NULL; + sd->vars_dirty = false; + sd->vars_ok = false; + sd->vars_received = 0x0; + + //warp player if ((i=pc->setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) { ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i); // try warping to a default map instead (church graveyard) - if (pc->setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { + if (pc->setpos(sd, mapindex->name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { // if we fail again clif->authfail_fd(sd->fd, 0); return false; @@ -1076,23 +1151,13 @@ 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); } - // message of the limited time of the account - if (expiration_time != 0) { // don't display if it's unlimited or unknow value - char tmpstr[1024]; - strftime(tmpstr, sizeof(tmpstr) - 1, msg_txt(501), localtime(&expiration_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S." - clif->wis_message(sd->fd, iMap->wisp_server_name, tmpstr, strlen(tmpstr)+1); + if (expiration_time != 0) { + sd->expiration_time = expiration_time; } /** @@ -1110,13 +1175,18 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim * Check if player have any item cooldowns on **/ pc->itemcd_do(sd,true); - + +#ifdef GP_BOUND_ITEMS + if( sd->status.party_id == 0 ) + pc->bound_clear(sd,IBT_PARTY); +#endif + /* [Ind/Hercules] */ sd->sc_display = NULL; sd->sc_display_count = 0; // Request all registries (auth is considered completed whence they arrive) - intif_request_registry(sd,7); + intif->request_registry(sd,7); return true; } @@ -1141,7 +1211,7 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) return 0; } - class_ = status_get_class(bl); + class_ = status->get_class(bl); if (!pcdb_checkid(class_)) { unsigned int max_hp = status_get_max_hp(bl); if ((pos == 1 && max_hp < 6000) || (pos == 2 && max_hp < 20000)) @@ -1150,7 +1220,7 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) return 0; //Wrong size } sd->hate_mob[pos] = class_; - pc_setglobalreg(sd,sg_info[pos].hate_var,class_+1); + pc_setglobalreg(sd,script->add_str(pc->sg_info[pos].hate_var),class_+1); clif->hate_info(sd, pos, class_, 1); return 1; } @@ -1162,55 +1232,58 @@ int pc_reg_received(struct map_session_data *sd) { int i,j, idx = 0; - sd->change_level_2nd = pc_readglobalreg(sd,"jobchange_level"); - sd->change_level_3rd = pc_readglobalreg(sd,"jobchange_level_3rd"); - sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER"); + sd->vars_ok = true; + + sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level")); + sd->change_level_3rd = pc_readglobalreg(sd,script->add_str("jobchange_level_3rd")); + sd->die_counter = pc_readglobalreg(sd,script->add_str("PC_DIE_COUNTER")); // Cash shop - sd->cashPoints = pc_readaccountreg(sd,"#CASHPOINTS"); - sd->kafraPoints = pc_readaccountreg(sd,"#KAFRAPOINTS"); + sd->cashPoints = pc_readaccountreg(sd,script->add_str("#CASHPOINTS")); + sd->kafraPoints = pc_readaccountreg(sd,script->add_str("#KAFRAPOINTS")); // Cooking Exp - sd->cook_mastery = pc_readglobalreg(sd,"COOK_MASTERY"); + sd->cook_mastery = pc_readglobalreg(sd,script->add_str("COOK_MASTERY")); if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) { // Better check for class rather than skill to prevent "skill resets" from unsetting this - sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID"); - sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT"); + sd->mission_mobid = pc_readglobalreg(sd,script->add_str("TK_MISSION_ID")); + sd->mission_count = pc_readglobalreg(sd,script->add_str("TK_MISSION_COUNT")); } //SG map and mob read [Komurka] for(i=0;i<MAX_PC_FEELHATE;i++) { //for now - someone need to make reading from txt/sql - if ((j = pc_readglobalreg(sd,sg_info[i].feel_var))!=0) { + if ((j = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].feel_var)))!=0) { sd->feel_map[i].index = j; - sd->feel_map[i].m = iMap->mapindex2mapid(j); + sd->feel_map[i].m = map->mapindex2mapid(j); } else { sd->feel_map[i].index = 0; sd->feel_map[i].m = -1; } - sd->hate_mob[i] = pc_readglobalreg(sd,sg_info[i].hate_var)-1; + sd->hate_mob[i] = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].hate_var))-1; } if ((i = pc->checkskill(sd,RG_PLAGIARISM)) > 0) { - sd->cloneskill_id = pc_readglobalreg(sd,"CLONE_SKILL"); + sd->cloneskill_id = pc_readglobalreg(sd,script->add_str("CLONE_SKILL")); if (sd->cloneskill_id > 0 && (idx = skill->get_index(sd->cloneskill_id))) { sd->status.skill[idx].id = sd->cloneskill_id; - sd->status.skill[idx].lv = pc_readglobalreg(sd,"CLONE_SKILL_LV"); + sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("CLONE_SKILL_LV")); if (sd->status.skill[idx].lv > i) sd->status.skill[idx].lv = i; sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } if ((i = pc->checkskill(sd,SC_REPRODUCE)) > 0) { - sd->reproduceskill_id = pc_readglobalreg(sd,"REPRODUCE_SKILL"); + sd->reproduceskill_id = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL")); if( sd->reproduceskill_id > 0 && (idx = skill->get_index(sd->reproduceskill_id))) { sd->status.skill[idx].id = sd->reproduceskill_id; - sd->status.skill[idx].lv = pc_readglobalreg(sd,"REPRODUCE_SKILL_LV"); + sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL_LV")); if( i < sd->status.skill[idx].lv) sd->status.skill[idx].lv = i; sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } + //Weird... maybe registries were reloaded? if (sd->state.active) return 0; @@ -1223,70 +1296,67 @@ int pc_reg_received(struct map_session_data *sd) // pet if (sd->status.pet_id > 0) - intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); + intif->request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); // Homunculus [albator] if( sd->status.hom_id > 0 ) - intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id); if( sd->status.mer_id > 0 ) - intif_mercenary_request(sd->status.mer_id, sd->status.char_id); + intif->mercenary_request(sd->status.mer_id, sd->status.char_id); if( sd->status.ele_id > 0 ) - intif_elemental_request(sd->status.ele_id, sd->status.char_id); + intif->elemental_request(sd->status.ele_id, sd->status.char_id); - iMap->addiddb(&sd->bl); - iMap->delnickdb(sd->status.char_id, sd->status.name); - if (!chrif_auth_finished(sd)) + map->addiddb(&sd->bl); + map->delnickdb(sd->status.char_id, sd->status.name); + if (!chrif->auth_finished(sd)) ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id); pc->load_combo(sd); - status_calc_pc(sd,1); - chrif_scdata_request(sd->status.account_id, sd->status.char_id); + status_calc_pc(sd,SCO_FIRST|SCO_FORCE); + chrif->scdata_request(sd->status.account_id, sd->status.char_id); - intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox - intif_request_questlog(sd); + intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox + intif->request_questlog(sd); if (sd->state.connect_new == 0 && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. sd->state.connect_new = 1; clif->pLoadEndAck(sd->fd, sd); } - pc->inventory_rentals(sd); - if( sd->sc.option & OPTION_INVISIBLE ) { sd->vd.class_ = INVISIBLE_CLASS; clif->message(sd->fd, msg_txt(11)); // Invisible: On // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + map->list[sd->bl.m].users_pvp--; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {// unregister the player for ranking - iTimer->delete_timer( sd->pvp_timer, pc->calc_pvprank_timer ); + if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {// unregister the player for ranking + timer->delete( sd->pvp_timer, pc->calc_pvprank_timer ); sd->pvp_timer = INVALID_TIMER; } clif->changeoption(&sd->bl); } if( npc->motd ) /* [Ind/Hercules] */ - run_script(npc->motd->u.scr.script, 0, sd->bl.id, fake_nd->bl.id); - + script->run(npc->motd->u.scr.script, 0, sd->bl.id, npc->fake_nd->bl.id); + return 1; } -static int pc_calc_skillpoint(struct map_session_data* sd) -{ +int pc_calc_skillpoint(struct map_session_data* sd) { int i,skill_lv,inf2,skill_point=0; nullpo_ret(sd); for(i=1;i<MAX_SKILL;i++){ if( (skill_lv = pc->checkskill2(sd,i)) > 0) { - inf2 = skill_db[i].inf2; + inf2 = skill->db[i].inf2; if((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) && - !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) //Do not count wedding/link skills. [Skotlex] + !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL|INF2_GUILD_SKILL)) //Do not count wedding/link skills. [Skotlex] ) { if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) skill_point += skill_lv; - else if(sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0) + else if(sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); } } @@ -1318,10 +1388,10 @@ int pc_calc_skilltree(struct map_session_data *sd) if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these sd->status.skill[i].id = 0; //First clear skills. /* permanent skills that must be re-checked */ - if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) { - switch( skill_db[i].nameid ) { + if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) { + switch( skill->db[i].nameid ) { case NV_TRICKDEAD: - if( (sd->class_&MAPID_UPPERMASK) != 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; @@ -1338,19 +1408,19 @@ int pc_calc_skilltree(struct map_session_data *sd) sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } - if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill_db[i].nameid >= DC_HUMMING && skill_db[i].nameid <= DC_SERVICEFORYOU ) + if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill->db[i].nameid >= DC_HUMMING && skill->db[i].nameid <= DC_SERVICEFORYOU ) { //Enable Bard/Dancer spirit linked skills. if( sd->status.sex ) { //Link dancer skills to bard. if( sd->status.skill[i-8].lv < 10 ) continue; - sd->status.skill[i].id = skill_db[i].nameid; + sd->status.skill[i].id = skill->db[i].nameid; sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill } else { //Link bard skills to dancer. if( sd->status.skill[i].lv < 10 ) continue; - sd->status.skill[i-8].id = skill_db[i-8].nameid; + sd->status.skill[i-8].id = skill->db[i-8].nameid; sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill } @@ -1359,7 +1429,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) { for( i = 0; i < MAX_SKILL; i++ ) { - switch(skill_db[i].nameid) { + switch(skill->db[i].nameid) { /** * Dummy skills must be added here otherwise they'll be displayed in the, * skill tree and since they have no icons they'll give resource errors @@ -1378,23 +1448,22 @@ int pc_calc_skilltree(struct map_session_data *sd) case WL_SUMMON_ATK_GROUND: case LG_OVERBRAND_BRANDISH: case LG_OVERBRAND_PLUSATK: - case WM_SEVERE_RAINSTORM_MELEE: continue; default: break; } - if( skill_db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL) ) + if( skill->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL) ) continue; //Only skills you can't have are npc/guild ones - if( skill_db[i].max > 0 ) - sd->status.skill[i].id = skill_db[i].nameid; + if( skill->db[i].max > 0 ) + sd->status.skill[i].id = skill->db[i].nameid; } return 0; } do { flag = 0; - for( i = 0; i < MAX_SKILL_TREE && (id = skill_tree[c][i].id) > 0; i++ ) { - int f, idx = skill_tree[c][i].idx; + for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { + int f, idx = pc->skill_tree[c][i].idx; if( sd->status.skill[idx].id ) continue; //Skill already known. @@ -1403,26 +1472,26 @@ int pc_calc_skilltree(struct map_session_data *sd) int j; for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { int k; - if((k=skill_tree[c][i].need[j].id)) { - int idx2 = skill_tree[c][i].need[j].idx; + if((k=pc->skill_tree[c][i].need[j].id)) { + int idx2 = pc->skill_tree[c][i].need[j].idx; if (sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED) k = 0; //Not learned. else if (sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; else k = pc->checkskill2(sd,idx2); - if (k < skill_tree[c][i].need[j].lv) { + if (k < pc->skill_tree[c][i].need[j].lv) { f = 0; break; } } } - if( sd->status.job_level < skill_tree[c][i].joblv ) + if( sd->status.job_level < pc->skill_tree[c][i].joblv ) f = 0; // job level requirement wasn't satisfied } if( f ) { int inf2; - inf2 = skill_db[idx].inf2; + inf2 = skill->db[idx].inf2; if(!sd->status.skill[idx].lv && ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || @@ -1432,7 +1501,7 @@ int pc_calc_skilltree(struct map_session_data *sd) continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills. sd->status.skill[idx].id = id; - + if(inf2&INF2_SPIRIT_SKILL) { //Spirit skills cannot be learned, they will only show up on your tree when you get buffed. sd->status.skill[idx].lv = 1; // need to manually specify a skill level sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill. @@ -1451,9 +1520,9 @@ int pc_calc_skilltree(struct map_session_data *sd) - (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 = skill_tree[c][i].id) > 0; i++ ) { - int idx = skill_tree[c][i].idx; - if( (skill_db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) + for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { + int idx = pc->skill_tree[c][i].idx; + if( (skill->db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) continue; //Do not include Quest/Wedding skills. if( sd->status.skill[idx].id == 0 ) { @@ -1471,7 +1540,7 @@ int pc_calc_skilltree(struct map_session_data *sd) } //Checks if you can learn a new skill after having leveled up a skill. -static void pc_check_skilltree(struct map_session_data *sd, int skill_id) +void pc_check_skilltree(struct map_session_data *sd, int skill_id) { int i,id=0,flag; int c=0; @@ -1488,22 +1557,22 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) c = pc->class2idx(c); do { flag = 0; - for( i = 0; i < MAX_SKILL_TREE && (id=skill_tree[c][i].id)>0; i++ ) { - int j, f = 1, k, idx = skill_tree[c][i].idx; + for( i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[c][i].id)>0; i++ ) { + int j, f = 1, k, idx = pc->skill_tree[c][i].idx; if( sd->status.skill[idx].id ) //Already learned continue; for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { - if( (k = skill_tree[c][i].need[j].id) ) { - int idx2 = skill_tree[c][i].need[j].idx; + if( (k = pc->skill_tree[c][i].need[j].id) ) { + int idx2 = pc->skill_tree[c][i].need[j].idx; if( sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED ) k = 0; //Not learned. else if( sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; else k = pc->checkskill2(sd,idx2); - if( k < skill_tree[c][i].need[j].lv ) { + if( k < pc->skill_tree[c][i].need[j].lv ) { f = 0; break; } @@ -1511,10 +1580,10 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) } if( !f ) continue; - if( sd->status.job_level < skill_tree[c][i].joblv ) + if( sd->status.job_level < pc->skill_tree[c][i].joblv ) continue; - j = skill_db[idx].inf2; + j = skill->db[idx].inf2; if( !sd->status.skill[idx].lv && ( (j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || j&INF2_WEDDING_SKILL || @@ -1523,6 +1592,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) continue; //Cannot be learned via normal means. sd->status.skill[idx].id = id; + flag = 1; } } while(flag); @@ -1538,7 +1608,7 @@ int pc_clean_skilltree(struct map_session_data *sd) sd->status.skill[i].id = 0; sd->status.skill[i].lv = 0; sd->status.skill[i].flag = 0; - } else if (sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0) { + } else if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].flag = 0; } @@ -1555,13 +1625,14 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) return c; - skill_point = pc_calc_skillpoint(sd); + skill_point = pc->calc_skillpoint(sd); - novice_skills = max_level[pc->class2idx(JOB_NOVICE)][1] - 1; + novice_skills = pc->max_level[pc->class2idx(JOB_NOVICE)][1] - 1; + sd->sktree.second = sd->sktree.third = 0; + // limit 1st class and above to novice job levels - if(skill_point < novice_skills) - { + if(skill_point < novice_skills) { c = MAPID_NOVICE; } // limit 2nd class and above to first class job levels (super novices are exempt) @@ -1574,7 +1645,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) { // 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 = max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1]; + sd->change_level_2nd = pc->max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1]; else sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - (sd->status.job_level - 1) @@ -1589,11 +1660,12 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) } - pc_setglobalreg (sd, "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; + 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 // regenerate change_level_3rd if (!sd->change_level_3rd) { @@ -1601,17 +1673,19 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) - (sd->status.job_level - 1) - (sd->change_level_2nd - 1) - novice_skills; - pc_setglobalreg (sd, "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)) + if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) { c &= 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); - + return c; } @@ -1643,9 +1717,9 @@ int pc_updateweightstatus(struct map_session_data *sd) // start new status change if( new_overweight == 1 ) - sc_start(&sd->bl, SC_WEIGHTOVER50, 100, 0, 0); + sc_start(NULL,&sd->bl, SC_WEIGHTOVER50, 100, 0, 0); else if( new_overweight == 2 ) - sc_start(&sd->bl, SC_WEIGHTOVER90, 100, 0, 0); + sc_start(NULL,&sd->bl, SC_WEIGHTOVER90, 100, 0, 0); // update overweight status sd->regen.state.overweight = new_overweight; @@ -1679,8 +1753,15 @@ int pc_disguise(struct map_session_data *sd, int 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_WEAPON,0); + clif->changelook(&sd->bl,LOOK_SHIELD,0); + clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); + } if (sd->bl.prev != NULL) { clif->spawn(&sd->bl); @@ -1689,11 +1770,17 @@ 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; + + if( (cd = (struct chat_data*)map->id2bl(sd->chatID)) ) + clif->dispchat(cd,0); + } } return 1; } -static int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id) +int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id) { int i; @@ -1729,7 +1816,7 @@ static int pc_bonus_autospell(struct s_autospell *spell, int max, short id, shor return 1; } -static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id) +int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id) { int i; @@ -1755,7 +1842,7 @@ static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short return 1; } -static int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, short rate, short arrow_rate, unsigned char flag) +int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, short rate, short arrow_rate, unsigned char flag) { int i; if (!(flag&(ATF_SHORT|ATF_LONG))) @@ -1784,13 +1871,10 @@ static int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, return 1; } -static int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill, unsigned char target) -{ +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; - for( i = 0; i < max && effect[i].skill; i++ ) - { - if( effect[i].id == id && effect[i].skill == skill && effect[i].target == target ) - { + 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; return 1; } @@ -1801,14 +1885,14 @@ static int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, e } effect[i].id = id; effect[i].rate = rate; - effect[i].skill = skill; + effect[i].skill = skill_id; effect[i].target = target; return 1; } -static int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race, int rate) -{ +int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race, int rate) { int i; + //Apply config rate adjustment settings. if (rate >= 0) { //Absolute drop. if (battle_config.item_rate_adddrop != 100) @@ -1855,8 +1939,7 @@ static int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id return 1; } -int pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short flag,const char *other_script,unsigned short pos,bool onskill) -{ +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; ARR_FIND(0, max, i, bonus[i].rate == 0); @@ -1886,7 +1969,7 @@ int pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short bonus[i].active = INVALID_TIMER; bonus[i].atk_type = flag; bonus[i].pos = pos; - bonus[i].bonus_script = aStrdup(script); + bonus[i].bonus_script = aStrdup(bonus_script); bonus[i].other_script = other_script?aStrdup(other_script):NULL; return 1; } @@ -1905,15 +1988,15 @@ int pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,c if( autobonus[i].bonus_script ) { int j; - ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos ); - if( j < EQI_MAX-1 ) - script_run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]); + ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos ); + if( j < EQI_MAX ) + script->run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]); } continue; } else { // Logout / Unequipped an item with an activated bonus - iTimer->delete_timer(autobonus[i].active,pc->endautobonus); + timer->delete(autobonus[i].active,pc->endautobonus); autobonus[i].active = INVALID_TIMER; } } @@ -1936,21 +2019,20 @@ int pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus) if( autobonus->other_script ) { int j; - ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos ); - if( j < EQI_MAX-1 ) - script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]); + ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos ); + if( j < EQI_MAX ) + script->run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]); } - autobonus->active = iTimer->add_timer(iTimer->gettick()+autobonus->duration, pc->endautobonus, sd->bl.id, (intptr_t)autobonus); + autobonus->active = timer->add(timer->gettick()+autobonus->duration, pc->endautobonus, sd->bl.id, (intptr_t)autobonus); sd->state.autobonus |= autobonus->pos; - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 0; } -int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_endautobonus(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); struct s_autobonus *autobonus = (struct s_autobonus *)data; nullpo_ret(sd); @@ -1958,7 +2040,7 @@ int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data) autobonus->active = INVALID_TIMER; sd->state.autobonus &= ~autobonus->pos; - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 0; } @@ -2030,13 +2112,12 @@ int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate, /*========================================== * Add a bonus(type) to player sd *------------------------------------------*/ -int pc_bonus(struct map_session_data *sd,int type,int val) -{ - struct status_data *status; +int pc_bonus(struct map_session_data *sd,int type,int val) { + struct status_data *bst; int bonus; nullpo_ret(sd); - status = &sd->base_status; + bst = &sd->base_status; switch(type){ case SP_STR: @@ -2050,58 +2131,57 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_ATK1: if(!sd->state.lr_flag) { - bonus = status->rhw.atk + val; - status->rhw.atk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->rhw.atk + val; + bst->rhw.atk = cap_value(bonus, 0, USHRT_MAX); } else if(sd->state.lr_flag == 1) { - bonus = status->lhw.atk + val; - status->lhw.atk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->lhw.atk + val; + bst->lhw.atk = cap_value(bonus, 0, USHRT_MAX); } break; case SP_ATK2: if(!sd->state.lr_flag) { - bonus = status->rhw.atk2 + val; - status->rhw.atk2 = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->rhw.atk2 + val; + bst->rhw.atk2 = cap_value(bonus, 0, USHRT_MAX); } else if(sd->state.lr_flag == 1) { - bonus = status->lhw.atk2 + val; - status->lhw.atk2 = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->lhw.atk2 + val; + bst->lhw.atk2 = cap_value(bonus, 0, USHRT_MAX); } break; case SP_BASE_ATK: if(sd->state.lr_flag != 2) { #ifdef RENEWAL - sd->bonus.eatk += val; - clif->updatestatus(sd,SP_ATK2); + bst->equip_atk += val; #else - bonus = status->batk + val; - status->batk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->batk + val; + bst->batk = cap_value(bonus, 0, USHRT_MAX); #endif } break; case SP_DEF1: if(sd->state.lr_flag != 2) { - bonus = status->def + val; + bonus = bst->def + val; #ifdef RENEWAL - status->def = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bst->def = cap_value(bonus, SHRT_MIN, SHRT_MAX); #else - status->def = cap_value(bonus, CHAR_MIN, CHAR_MAX); + bst->def = cap_value(bonus, CHAR_MIN, CHAR_MAX); #endif } break; case SP_DEF2: if(sd->state.lr_flag != 2) { - bonus = status->def2 + val; - status->def2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->def2 + val; + bst->def2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_MDEF1: if(sd->state.lr_flag != 2) { - bonus = status->mdef + val; + bonus = bst->mdef + val; #ifdef RENEWAL - status->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bst->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX); #else - status->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX); + bst->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX); #endif if( sd->state.lr_flag == 3 ) {//Shield, used for royal guard sd->bonus.shieldmdef += bonus; @@ -2110,33 +2190,33 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_MDEF2: if(sd->state.lr_flag != 2) { - bonus = status->mdef2 + val; - status->mdef2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->mdef2 + val; + bst->mdef2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_HIT: if(sd->state.lr_flag != 2) { - bonus = status->hit + val; - status->hit = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->hit + val; + bst->hit = cap_value(bonus, SHRT_MIN, SHRT_MAX); } else sd->bonus.arrow_hit+=val; break; case SP_FLEE1: if(sd->state.lr_flag != 2) { - bonus = status->flee + val; - status->flee = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->flee + val; + bst->flee = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_FLEE2: if(sd->state.lr_flag != 2) { - bonus = status->flee2 + val*10; - status->flee2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->flee2 + val*10; + bst->flee2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_CRITICAL: if(sd->state.lr_flag != 2) { - bonus = status->cri + val*10; - status->cri = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->cri + val*10; + bst->cri = cap_value(bonus, SHRT_MIN, SHRT_MAX); } else sd->bonus.arrow_cri += val*10; break; @@ -2145,8 +2225,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) ShowError("pc_bonus: SP_ATKELE: Invalid element %d\n", val); break; } - switch (sd->state.lr_flag) - { + switch (sd->state.lr_flag) { case 2: switch (sd->status.weapon) { case W_BOW: @@ -2156,7 +2235,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case W_SHOTGUN: case W_GRENADE: //Become weapon element. - status->rhw.ele=val; + bst->rhw.ele=val; break; default: //Become arrow element. sd->bonus.arrow_ele=val; @@ -2164,10 +2243,10 @@ int pc_bonus(struct map_session_data *sd,int type,int val) } break; case 1: - status->lhw.ele=val; + bst->lhw.ele=val; break; default: - status->rhw.ele=val; + bst->rhw.ele=val; break; } break; @@ -2177,21 +2256,21 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; } if(sd->state.lr_flag != 2) - status->def_ele=val; + bst->def_ele=val; break; case SP_MAXHP: if(sd->state.lr_flag == 2) break; - val += (int)status->max_hp; + val += (int)bst->max_hp; //Negative bonuses will underflow, this will be handled in status_calc_pc through casting //If this is called outside of status_calc_pc, you'd better pray they do not underflow and end with UINT_MAX max_hp. - status->max_hp = (unsigned int)val; + bst->max_hp = (unsigned int)val; break; case SP_MAXSP: if(sd->state.lr_flag == 2) break; - val += (int)status->max_sp; - status->max_sp = (unsigned int)val; + val += (int)bst->max_sp; + bst->max_sp = (unsigned int)val; break; #ifndef RENEWAL_CAST case SP_VARCASTRATE: @@ -2222,14 +2301,14 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case W_GATLING: case W_SHOTGUN: case W_GRENADE: - status->rhw.range += val; + bst->rhw.range += val; } break; case 1: - status->lhw.range += val; + bst->lhw.range += val; break; default: - status->rhw.range += val; + bst->rhw.range += val; break; } break; @@ -2248,9 +2327,9 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case SP_ASPD_RATE: //Stackable increase - Made it linear as per rodatazone if(sd->state.lr_flag != 2) #ifndef RENEWAL_ASPD - status->aspd_rate -= 10*val; + bst->aspd_rate -= 10*val; #else - status->aspd_rate2 += val; + bst->aspd_rate2 += val; #endif break; case SP_HP_RECOV_RATE: @@ -2630,11 +2709,13 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_ADD_VARIABLECAST: if(sd->state.lr_flag != 2) - sd->bonus.add_varcast += val; - break; #endif + case SP_ADD_MONSTER_DROP_CHAINITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, (1<<RC_BOSS)|(1<<RC_NONBOSS), 10000); + break; default: ShowWarning("pc_bonus: unknown type %d %d !\n",type,val); break; @@ -2652,593 +2733,591 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val) nullpo_ret(sd); switch(type){ - case SP_ADDELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_ADDELE: Invalid element %d\n", type2); + case SP_ADDELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_ADDELE: Invalid element %d\n", type2); + break; + } + if(!sd->state.lr_flag) + sd->right_weapon.addele[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addele[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addele[type2]+=val; break; - } - if(!sd->state.lr_flag) - sd->right_weapon.addele[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addele[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addele[type2]+=val; - break; - case SP_ADDRACE: - if(!sd->state.lr_flag) - sd->right_weapon.addrace[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addrace[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addrace[type2]+=val; - break; - case SP_ADDSIZE: - if(!sd->state.lr_flag) - sd->right_weapon.addsize[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addsize[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addsize[type2]+=val; - break; - case SP_SUBELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_SUBELE: Invalid element %d\n", type2); + case SP_ADDRACE: + if(!sd->state.lr_flag) + sd->right_weapon.addrace[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addrace[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addrace[type2]+=val; break; - } - if(sd->state.lr_flag != 2) - sd->subele[type2]+=val; - break; - case SP_SUBRACE: - if(sd->state.lr_flag != 2) - sd->subrace[type2]+=val; - break; - case SP_ADDEFF: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect): %d is not supported.\n", type2); + case SP_ADDSIZE: + if(!sd->state.lr_flag) + sd->right_weapon.addsize[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addsize[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addsize[type2]+=val; break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, 0); - break; - case SP_ADDEFF2: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect2): %d is not supported.\n", type2); + case SP_SUBELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_SUBELE: Invalid element %d\n", type2); + break; + } + if(sd->state.lr_flag != 2) + sd->subele[type2]+=val; break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, ATF_SELF); - break; - case SP_RESEFF: - if (type2 < SC_COMMON_MIN || type2 > SC_COMMON_MAX) { - ShowWarning("pc_bonus2 (Resist Effect): %d is not supported.\n", type2); + case SP_SUBRACE: + if(sd->state.lr_flag != 2) + sd->subrace[type2]+=val; break; - } - if(sd->state.lr_flag == 2) + case SP_ADDEFF: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, 0); break; - i = sd->reseff[type2-SC_COMMON_MIN]+val; - sd->reseff[type2-SC_COMMON_MIN]= cap_value(i, 0, 10000); - break; - case SP_MAGIC_ADDELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_MAGIC_ADDELE: Invalid element %d\n", type2); + case SP_ADDEFF2: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect2): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, ATF_SELF); break; - } - if(sd->state.lr_flag != 2) - sd->magic_addele[type2]+=val; - break; - case SP_MAGIC_ADDRACE: - if(sd->state.lr_flag != 2) - sd->magic_addrace[type2]+=val; - break; - case SP_MAGIC_ADDSIZE: - if(sd->state.lr_flag != 2) - sd->magic_addsize[type2]+=val; - break; - case SP_MAGIC_ATK_ELE: - if(sd->state.lr_flag != 2) - sd->magic_atk_ele[type2]+=val; - break; - case SP_ADD_DAMAGE_CLASS: - switch (sd->state.lr_flag) { - case 0: //Right hand - ARR_FIND(0, ARRAYLENGTH(sd->right_weapon.add_dmg), i, sd->right_weapon.add_dmg[i].rate == 0 || sd->right_weapon.add_dmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->right_weapon.add_dmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n", ARRAYLENGTH(sd->right_weapon.add_dmg)); + case SP_RESEFF: + if (type2 < SC_COMMON_MIN || type2 > SC_COMMON_MAX) { + ShowWarning("pc_bonus2 (Resist Effect): %d is not supported.\n", type2); break; } - sd->right_weapon.add_dmg[i].class_ = type2; - sd->right_weapon.add_dmg[i].rate += val; - if (!sd->right_weapon.add_dmg[i].rate) //Shift the rest of elements up. - memmove(&sd->right_weapon.add_dmg[i], &sd->right_weapon.add_dmg[i+1], sizeof(sd->right_weapon.add_dmg) - (i+1)*sizeof(sd->right_weapon.add_dmg[0])); + if(sd->state.lr_flag == 2) + break; + i = sd->reseff[type2-SC_COMMON_MIN]+val; + sd->reseff[type2-SC_COMMON_MIN]= cap_value(i, 0, 10000); break; - case 1: //Left hand - ARR_FIND(0, ARRAYLENGTH(sd->left_weapon.add_dmg), i, sd->left_weapon.add_dmg[i].rate == 0 || sd->left_weapon.add_dmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->left_weapon.add_dmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n", ARRAYLENGTH(sd->left_weapon.add_dmg)); + case SP_MAGIC_ADDELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_MAGIC_ADDELE: Invalid element %d\n", type2); break; } - sd->left_weapon.add_dmg[i].class_ = type2; - sd->left_weapon.add_dmg[i].rate += val; - if (!sd->left_weapon.add_dmg[i].rate) //Shift the rest of elements up. - memmove(&sd->left_weapon.add_dmg[i], &sd->left_weapon.add_dmg[i+1], sizeof(sd->left_weapon.add_dmg) - (i+1)*sizeof(sd->left_weapon.add_dmg[0])); + if(sd->state.lr_flag != 2) + sd->magic_addele[type2]+=val; break; - } - break; - case SP_ADD_MAGIC_DAMAGE_CLASS: - if(sd->state.lr_flag == 2) + case SP_MAGIC_ADDRACE: + if(sd->state.lr_flag != 2) + sd->magic_addrace[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->add_mdmg), i, sd->add_mdmg[i].rate == 0 || sd->add_mdmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_mdmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class magic dmg bonuses per character!\n", ARRAYLENGTH(sd->add_mdmg)); + case SP_MAGIC_ADDSIZE: + if(sd->state.lr_flag != 2) + sd->magic_addsize[type2]+=val; break; - } - sd->add_mdmg[i].class_ = type2; - sd->add_mdmg[i].rate += val; - if (!sd->add_mdmg[i].rate) //Shift the rest of elements up. - memmove(&sd->add_mdmg[i], &sd->add_mdmg[i+1], sizeof(sd->add_mdmg) - (i+1)*sizeof(sd->add_mdmg[0])); - break; - case SP_ADD_DEF_CLASS: - if(sd->state.lr_flag == 2) + case SP_MAGIC_ATK_ELE: + if(sd->state.lr_flag != 2) + sd->magic_atk_ele[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->add_def), i, sd->add_def[i].rate == 0 || sd->add_def[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_def)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class def bonuses per character!\n", ARRAYLENGTH(sd->add_def)); + case SP_ADD_DAMAGE_CLASS: + switch (sd->state.lr_flag) { + case 0: //Right hand + ARR_FIND(0, ARRAYLENGTH(sd->right_weapon.add_dmg), i, sd->right_weapon.add_dmg[i].rate == 0 || sd->right_weapon.add_dmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->right_weapon.add_dmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class dmg bonuses per character!\n", + ARRAYLENGTH(sd->right_weapon.add_dmg)); + break; + } + sd->right_weapon.add_dmg[i].class_ = type2; + sd->right_weapon.add_dmg[i].rate += val; + if (!sd->right_weapon.add_dmg[i].rate) //Shift the rest of elements up. + memmove(&sd->right_weapon.add_dmg[i], &sd->right_weapon.add_dmg[i+1], sizeof(sd->right_weapon.add_dmg) - (i+1)*sizeof(sd->right_weapon.add_dmg[0])); + break; + case 1: //Left hand + ARR_FIND(0, ARRAYLENGTH(sd->left_weapon.add_dmg), i, sd->left_weapon.add_dmg[i].rate == 0 || sd->left_weapon.add_dmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->left_weapon.add_dmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class dmg bonuses per character!\n", + ARRAYLENGTH(sd->left_weapon.add_dmg)); + break; + } + sd->left_weapon.add_dmg[i].class_ = type2; + sd->left_weapon.add_dmg[i].rate += val; + if (!sd->left_weapon.add_dmg[i].rate) //Shift the rest of elements up. + memmove(&sd->left_weapon.add_dmg[i], &sd->left_weapon.add_dmg[i+1], sizeof(sd->left_weapon.add_dmg) - (i+1)*sizeof(sd->left_weapon.add_dmg[0])); + break; + } break; - } - sd->add_def[i].class_ = type2; - sd->add_def[i].rate += val; - if (!sd->add_def[i].rate) //Shift the rest of elements up. - memmove(&sd->add_def[i], &sd->add_def[i+1], sizeof(sd->add_def) - (i+1)*sizeof(sd->add_def[0])); - break; - case SP_ADD_MDEF_CLASS: - if(sd->state.lr_flag == 2) + case SP_ADD_MAGIC_DAMAGE_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_mdmg), i, sd->add_mdmg[i].rate == 0 || sd->add_mdmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_mdmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class magic dmg bonuses per character!\n", ARRAYLENGTH(sd->add_mdmg)); + break; + } + sd->add_mdmg[i].class_ = type2; + sd->add_mdmg[i].rate += val; + if (!sd->add_mdmg[i].rate) //Shift the rest of elements up. + memmove(&sd->add_mdmg[i], &sd->add_mdmg[i+1], sizeof(sd->add_mdmg) - (i+1)*sizeof(sd->add_mdmg[0])); break; - ARR_FIND(0, ARRAYLENGTH(sd->add_mdef), i, sd->add_mdef[i].rate == 0 || sd->add_mdef[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_mdef)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class mdef bonuses per character!\n", ARRAYLENGTH(sd->add_mdef)); + case SP_ADD_DEF_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_def), i, sd->add_def[i].rate == 0 || sd->add_def[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_def)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class def bonuses per character!\n", ARRAYLENGTH(sd->add_def)); + break; + } + sd->add_def[i].class_ = type2; + sd->add_def[i].rate += val; + if (!sd->add_def[i].rate) //Shift the rest of elements up. + memmove(&sd->add_def[i], &sd->add_def[i+1], sizeof(sd->add_def) - (i+1)*sizeof(sd->add_def[0])); break; - } - sd->add_mdef[i].class_ = type2; - sd->add_mdef[i].rate += val; - if (!sd->add_mdef[i].rate) //Shift the rest of elements up. - memmove(&sd->add_mdef[i], &sd->add_mdef[i+1], sizeof(sd->add_mdef) - (i+1)*sizeof(sd->add_mdef[0])); - break; - case SP_HP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.hp_drain[RC_NONBOSS].per += val; - sd->right_weapon.hp_drain[RC_BOSS].rate += type2; - sd->right_weapon.hp_drain[RC_BOSS].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.hp_drain[RC_NONBOSS].per += val; - sd->left_weapon.hp_drain[RC_BOSS].rate += type2; - sd->left_weapon.hp_drain[RC_BOSS].per += val; - } - break; - case SP_HP_DRAIN_VALUE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[RC_NONBOSS].value += type2; - sd->right_weapon.hp_drain[RC_NONBOSS].type = val; - sd->right_weapon.hp_drain[RC_BOSS].value += type2; - sd->right_weapon.hp_drain[RC_BOSS].type = val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[RC_NONBOSS].value += type2; - sd->left_weapon.hp_drain[RC_NONBOSS].type = val; - sd->left_weapon.hp_drain[RC_BOSS].value += type2; - sd->left_weapon.hp_drain[RC_BOSS].type = val; - } - break; - case SP_SP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].per += val; - sd->right_weapon.sp_drain[RC_BOSS].rate += type2; - sd->right_weapon.sp_drain[RC_BOSS].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].per += val; - sd->left_weapon.sp_drain[RC_BOSS].rate += type2; - sd->left_weapon.sp_drain[RC_BOSS].per += val; - } - break; - case SP_SP_DRAIN_VALUE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].value += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].type = val; - sd->right_weapon.sp_drain[RC_BOSS].value += type2; - sd->right_weapon.sp_drain[RC_BOSS].type = val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].value += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].type = val; - sd->left_weapon.sp_drain[RC_BOSS].value += type2; - sd->left_weapon.sp_drain[RC_BOSS].type = val; - } - break; - case SP_SP_VANISH_RATE: - if(sd->state.lr_flag != 2) { - sd->bonus.sp_vanish_rate += type2; - sd->bonus.sp_vanish_per += val; - } - break; - case SP_GET_ZENY_NUM: - if(sd->state.lr_flag != 2 && sd->bonus.get_zeny_rate < val) { - sd->bonus.get_zeny_rate = val; - sd->bonus.get_zeny_num = type2; - } - break; - case SP_ADD_GET_ZENY_NUM: - if(sd->state.lr_flag != 2) { - sd->bonus.get_zeny_rate += val; - sd->bonus.get_zeny_num += type2; - } - break; - case SP_WEAPON_COMA_ELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_WEAPON_COMA_ELE: Invalid element %d\n", type2); + case SP_ADD_MDEF_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_mdef), i, sd->add_mdef[i].rate == 0 || sd->add_mdef[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_mdef)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class mdef bonuses per character!\n", ARRAYLENGTH(sd->add_mdef)); + break; + } + sd->add_mdef[i].class_ = type2; + sd->add_mdef[i].rate += val; + if (!sd->add_mdef[i].rate) //Shift the rest of elements up. + memmove(&sd->add_mdef[i], &sd->add_mdef[i+1], sizeof(sd->add_mdef) - (i+1)*sizeof(sd->add_mdef[0])); break; - } - if(sd->state.lr_flag == 2) + case SP_HP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.hp_drain[RC_NONBOSS].per += val; + sd->right_weapon.hp_drain[RC_BOSS].rate += type2; + sd->right_weapon.hp_drain[RC_BOSS].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.hp_drain[RC_NONBOSS].per += val; + sd->left_weapon.hp_drain[RC_BOSS].rate += type2; + sd->left_weapon.hp_drain[RC_BOSS].per += val; + } break; - sd->weapon_coma_ele[type2] += val; - sd->special_state.bonus_coma = 1; - break; - case SP_WEAPON_COMA_RACE: - if(sd->state.lr_flag == 2) + case SP_HP_DRAIN_VALUE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[RC_NONBOSS].value += type2; + sd->right_weapon.hp_drain[RC_NONBOSS].type = val; + sd->right_weapon.hp_drain[RC_BOSS].value += type2; + sd->right_weapon.hp_drain[RC_BOSS].type = val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[RC_NONBOSS].value += type2; + sd->left_weapon.hp_drain[RC_NONBOSS].type = val; + sd->left_weapon.hp_drain[RC_BOSS].value += type2; + sd->left_weapon.hp_drain[RC_BOSS].type = val; + } break; - sd->weapon_coma_race[type2] += val; - sd->special_state.bonus_coma = 1; - break; - case SP_WEAPON_ATK: - if(sd->state.lr_flag != 2) - sd->weapon_atk[type2]+=val; - break; - case SP_WEAPON_ATK_RATE: - if(sd->state.lr_flag != 2) - sd->weapon_atk_rate[type2]+=val; - break; - case SP_CRITICAL_ADDRACE: - if(sd->state.lr_flag != 2) - sd->critaddrace[type2] += val*10; - break; - case SP_ADDEFF_WHENHIT: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect when hit): %d is not supported.\n", type2); + case SP_SP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].per += val; + sd->right_weapon.sp_drain[RC_BOSS].rate += type2; + sd->right_weapon.sp_drain[RC_BOSS].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].per += val; + sd->left_weapon.sp_drain[RC_BOSS].rate += type2; + sd->left_weapon.sp_drain[RC_BOSS].per += val; + } break; - } - if(sd->state.lr_flag != 2) - pc_bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, val, 0, 0); - break; - case SP_SKILL_ATK: - if(sd->state.lr_flag == 2) + case SP_SP_DRAIN_VALUE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].value += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].type = val; + sd->right_weapon.sp_drain[RC_BOSS].value += type2; + sd->right_weapon.sp_drain[RC_BOSS].type = val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].value += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].type = val; + sd->left_weapon.sp_drain[RC_BOSS].value += type2; + sd->left_weapon.sp_drain[RC_BOSS].type = val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == 0 || sd->skillatk[i].id == type2); - if (i == ARRAYLENGTH(sd->skillatk)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillAtk reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillatk), type2, val); + case SP_SP_VANISH_RATE: + if(sd->state.lr_flag != 2) { + sd->bonus.sp_vanish_rate += type2; + sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per,val); + sd->bonus.sp_vanish_trigger=0; + } break; - } - if (sd->skillatk[i].id == type2) - sd->skillatk[i].val += val; - else { - sd->skillatk[i].id = type2; - sd->skillatk[i].val = val; - } - break; - case SP_SKILL_HEAL: - if(sd->state.lr_flag == 2) + case SP_GET_ZENY_NUM: + if(sd->state.lr_flag != 2 && sd->bonus.get_zeny_rate < val) { + sd->bonus.get_zeny_rate = val; + sd->bonus.get_zeny_num = type2; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == 0 || sd->skillheal[i].id == type2); - if (i == ARRAYLENGTH(sd->skillheal)) - { // Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillHeal reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillheal), type2, val); + case SP_ADD_GET_ZENY_NUM: + if(sd->state.lr_flag != 2) { + sd->bonus.get_zeny_rate += val; + sd->bonus.get_zeny_num += type2; + } break; - } - if (sd->skillheal[i].id == type2) - sd->skillheal[i].val += val; - else { - sd->skillheal[i].id = type2; - sd->skillheal[i].val = val; - } - break; - case SP_SKILL_HEAL2: - if(sd->state.lr_flag == 2) + case SP_WEAPON_COMA_ELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_WEAPON_COMA_ELE: Invalid element %d\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->weapon_coma_ele[type2] += val; + sd->special_state.bonus_coma = 1; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == 0 || sd->skillheal2[i].id == type2); - if (i == ARRAYLENGTH(sd->skillheal2)) - { // Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillHeal2 reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillheal2), type2, val); + case SP_WEAPON_COMA_RACE: + if(sd->state.lr_flag == 2) + break; + sd->weapon_coma_race[type2] += val; + sd->special_state.bonus_coma = 1; break; - } - if (sd->skillheal2[i].id == type2) - sd->skillheal2[i].val += val; - else { - sd->skillheal2[i].id = type2; - sd->skillheal2[i].val = val; - } - break; - case SP_ADD_SKILL_BLOW: - if(sd->state.lr_flag == 2) + case SP_WEAPON_ATK: + if(sd->state.lr_flag != 2) + sd->weapon_atk[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2); - if (i == ARRAYLENGTH(sd->skillblown)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillBlown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillblown), type2, val); + case SP_WEAPON_ATK_RATE: + if(sd->state.lr_flag != 2) + sd->weapon_atk_rate[type2]+=val; break; - } - if(sd->skillblown[i].id == type2) - sd->skillblown[i].val += val; - else { - sd->skillblown[i].id = type2; - sd->skillblown[i].val = val; - } - break; -#ifndef RENEWAL_CAST - case SP_VARCASTRATE: -#endif - case SP_CASTRATE: - if(sd->state.lr_flag == 2) + case SP_CRITICAL_ADDRACE: + if(sd->state.lr_flag != 2) + sd->critaddrace[type2] += val*10; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 %s reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", - -#ifndef RENEWAL_CAST - "bCastRate", -#else - "bVariableCastrate", -#endif - - ARRAYLENGTH(sd->skillcast), type2, val); + case SP_ADDEFF_WHENHIT: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect when hit): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag != 2) + pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, val, 0, 0); break; - } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val += val; - else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val = val; - } - break; - - case SP_FIXCASTRATE: - if(sd->state.lr_flag == 2) + case SP_SKILL_ATK: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == 0 || sd->skillatk[i].id == type2); + if (i == ARRAYLENGTH(sd->skillatk)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillAtk reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillatk), type2, val); + break; + } + if (sd->skillatk[i].id == type2) + sd->skillatk[i].val += val; + else { + sd->skillatk[i].id = type2; + sd->skillatk[i].val = val; + } + break; + case SP_SKILL_HEAL: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == 0 || sd->skillheal[i].id == type2); + if (i == ARRAYLENGTH(sd->skillheal)) { + // Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillHeal reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillheal), type2, val); + break; + } + if (sd->skillheal[i].id == type2) + sd->skillheal[i].val += val; + else { + sd->skillheal[i].id = type2; + sd->skillheal[i].val = val; + } + break; + case SP_SKILL_HEAL2: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == 0 || sd->skillheal2[i].id == type2); + if (i == ARRAYLENGTH(sd->skillheal2)) { + // Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillHeal2 reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillheal2), type2, val); + break; + } + if (sd->skillheal2[i].id == type2) + sd->skillheal2[i].val += val; + else { + sd->skillheal2[i].id = type2; + sd->skillheal2[i].val = val; + } + break; + case SP_ADD_SKILL_BLOW: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2); + if (i == ARRAYLENGTH(sd->skillblown)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillBlown reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillblown), type2, val); + break; + } + if(sd->skillblown[i].id == type2) + sd->skillblown[i].val += val; + else { + sd->skillblown[i].id = type2; + sd->skillblown[i].val = val; + } break; + #ifndef RENEWAL_CAST + case SP_VARCASTRATE: + #endif + case SP_CASTRATE: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcast)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 %s reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", - ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); + #ifndef RENEWAL_CAST + "bCastRate", + #else + "bVariableCastrate", + #endif - if (i == ARRAYLENGTH(sd->skillfixcastrate)) + ARRAYLENGTH(sd->skillcast), type2, val); + break; + } + if(sd->skillcast[i].id == type2) + sd->skillcast[i].val += val; + else { + sd->skillcast[i].id = type2; + sd->skillcast[i].val = val; + } + break; - { + case SP_FIXCASTRATE: + if(sd->state.lr_flag == 2) + break; - ShowDebug("run_script: bonus2 bFixedCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcastrate), type2, val); - break; - } + ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); - if(sd->skillfixcastrate[i].id == type2) - sd->skillfixcastrate[i].val += val; + if (i == ARRAYLENGTH(sd->skillfixcastrate)) { + ShowDebug("script->run: bonus2 bFixedCastrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillfixcastrate), type2, val); + break; + } - else { - sd->skillfixcastrate[i].id = type2; - sd->skillfixcastrate[i].val = val; - } + if(sd->skillfixcastrate[i].id == type2) + sd->skillfixcastrate[i].val += val; - break; + else { + sd->skillfixcastrate[i].id = type2; + sd->skillfixcastrate[i].val = val; + } - case SP_HP_LOSS_RATE: - if(sd->state.lr_flag != 2) { - sd->hp_loss.value = type2; - sd->hp_loss.rate = val; - } - break; - case SP_HP_REGEN_RATE: - if(sd->state.lr_flag != 2) { - sd->hp_regen.value = type2; - sd->hp_regen.rate = val; - } - break; - case SP_ADDRACE2: - if (!(type2 > RC2_NONE && type2 < RC2_MAX)) break; - if(sd->state.lr_flag != 2) - sd->right_weapon.addrace2[type2] += val; - else - sd->left_weapon.addrace2[type2] += val; - break; - case SP_SUBSIZE: - if(sd->state.lr_flag != 2) - sd->subsize[type2]+=val; - break; - case SP_SUBRACE2: - if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + + case SP_HP_LOSS_RATE: + if(sd->state.lr_flag != 2) { + sd->hp_loss.value = type2; + sd->hp_loss.rate = val; + } break; - if(sd->state.lr_flag != 2) - sd->subrace2[type2]+=val; - break; - case SP_ADD_ITEM_HEAL_RATE: - if(sd->state.lr_flag == 2) + case SP_HP_REGEN_RATE: + if(sd->state.lr_flag != 2) { + sd->hp_regen.value = type2; + sd->hp_regen.rate = val; + } break; - if (type2 < MAX_ITEMGROUP) { //Group bonus - sd->itemgrouphealrate[type2] += val; + case SP_ADDRACE2: + if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + break; + if(sd->state.lr_flag != 2) + sd->right_weapon.addrace2[type2] += val; + else + sd->left_weapon.addrace2[type2] += val; break; - } - //Standard item bonus. - for(i=0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid && sd->itemhealrate[i].nameid != type2; i++); - if(i == ARRAYLENGTH(sd->itemhealrate)) { - ShowWarning("pc_bonus2: Reached max (%d) number of item heal bonuses per character!\n", ARRAYLENGTH(sd->itemhealrate)); + case SP_SUBSIZE: + if(sd->state.lr_flag != 2) + sd->subsize[type2]+=val; break; - } - sd->itemhealrate[i].nameid = type2; - sd->itemhealrate[i].rate += val; - break; - case SP_EXP_ADDRACE: - if(sd->state.lr_flag != 2) - sd->expaddrace[type2]+=val; - break; - case SP_SP_GAIN_RACE: - if(sd->state.lr_flag != 2) - sd->sp_gain_race[type2]+=val; - break; - case SP_ADD_MONSTER_DROP_ITEM: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); - break; - case SP_ADD_MONSTER_DROP_ITEMGROUP: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, type2, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); - break; - case SP_SP_LOSS_RATE: - if(sd->state.lr_flag != 2) { - sd->sp_loss.value = type2; - sd->sp_loss.rate = val; - } - break; - case SP_SP_REGEN_RATE: - if(sd->state.lr_flag != 2) { - sd->sp_regen.value = type2; - sd->sp_regen.rate = val; - } - break; - case SP_HP_DRAIN_VALUE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[type2].value += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[type2].value += val; - } - break; - case SP_SP_DRAIN_VALUE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[type2].value += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[type2].value += val; - } - break; - case SP_IGNORE_MDEF_RATE: - if(sd->state.lr_flag != 2) - sd->ignore_mdef[type2] += val; - break; - case SP_IGNORE_DEF_RATE: - if(sd->state.lr_flag != 2) - sd->ignore_def[type2] += val; - break; - case SP_SP_GAIN_RACE_ATTACK: - if(sd->state.lr_flag != 2) - sd->sp_gain_race_attack[type2] = cap_value(sd->sp_gain_race_attack[type2] + val, 0, INT16_MAX); - break; - case SP_HP_GAIN_RACE_ATTACK: - if(sd->state.lr_flag != 2) - sd->hp_gain_race_attack[type2] = cap_value(sd->hp_gain_race_attack[type2] + val, 0, INT16_MAX); - break; - case SP_SKILL_USE_SP_RATE: //bonus2 bSkillUseSPrate,n,x; - if(sd->state.lr_flag == 2) + case SP_SUBRACE2: + if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + break; + if(sd->state.lr_flag != 2) + sd->subrace2[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillusesprate), i, sd->skillusesprate[i].id == 0 || sd->skillusesprate[i].id == type2); - if (i == ARRAYLENGTH(sd->skillusesprate)) { - ShowDebug("run_script: bonus2 bSkillUseSPrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillusesprate), type2, val); + case SP_ADD_ITEM_HEAL_RATE: + if(sd->state.lr_flag == 2) + break; + //Standard item bonus. + for(i=0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid && sd->itemhealrate[i].nameid != type2; i++); + if (i == ARRAYLENGTH(sd->itemhealrate)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of item heal bonuses per character!\n", ARRAYLENGTH(sd->itemhealrate)); + break; + } + sd->itemhealrate[i].nameid = type2; + sd->itemhealrate[i].rate += val; break; - } - if (sd->skillusesprate[i].id == type2) - sd->skillusesprate[i].val += val; - else { - sd->skillusesprate[i].id = type2; - sd->skillusesprate[i].val = val; - } - break; - case SP_SKILL_COOLDOWN: - if(sd->state.lr_flag == 2) + case SP_EXP_ADDRACE: + if(sd->state.lr_flag != 2) + sd->expaddrace[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcooldown)) - { - ShowDebug("run_script: bonus2 bSkillCoolDown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillcooldown), type2, val); + case SP_SP_GAIN_RACE: + if(sd->state.lr_flag != 2) + sd->sp_gain_race[type2]+=val; break; - } - if (sd->skillcooldown[i].id == type2) - sd->skillcooldown[i].val += val; - else { - sd->skillcooldown[i].id = type2; - sd->skillcooldown[i].val = val; - } - break; - case SP_SKILL_FIXEDCAST: - if(sd->state.lr_flag == 2) + case SP_ADD_MONSTER_DROP_ITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); break; - ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillfixcast)) - { - ShowDebug("run_script: bonus2 bSkillFixedCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcast), type2, val); + case SP_SP_LOSS_RATE: + if(sd->state.lr_flag != 2) { + sd->sp_loss.value = type2; + sd->sp_loss.rate = val; + } break; - } - if (sd->skillfixcast[i].id == type2) - sd->skillfixcast[i].val += val; - else { - sd->skillfixcast[i].id = type2; - sd->skillfixcast[i].val = val; - } - break; - case SP_SKILL_VARIABLECAST: - if(sd->state.lr_flag == 2) + case SP_SP_REGEN_RATE: + if(sd->state.lr_flag != 2) { + sd->sp_regen.value = type2; + sd->sp_regen.rate = val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillvarcast)) - { - ShowDebug("run_script: bonus2 bSkillVariableCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillvarcast), type2, val); + case SP_HP_DRAIN_VALUE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[type2].value += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[type2].value += val; + } break; - } - if (sd->skillvarcast[i].id == type2) - sd->skillvarcast[i].val += val; - else { - sd->skillvarcast[i].id = type2; - sd->skillvarcast[i].val = val; - } - break; -#ifdef RENEWAL_CAST - case SP_VARCASTRATE: - if(sd->state.lr_flag == 2) + case SP_SP_DRAIN_VALUE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[type2].value += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[type2].value += val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) - { - ShowDebug("run_script: bonus2 bVariableCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",ARRAYLENGTH(sd->skillcast), type2, val); + case SP_IGNORE_MDEF_RATE: + if(sd->state.lr_flag != 2) + sd->ignore_mdef[type2] += val; break; - } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val -= val; - else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val -= val; - } - break; -#endif - case SP_SKILL_USE_SP: //bonus2 bSkillUseSP,n,x; - if(sd->state.lr_flag == 2) + case SP_IGNORE_DEF_RATE: + if(sd->state.lr_flag != 2) + sd->ignore_def[type2] += val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2); - if (i == ARRAYLENGTH(sd->skillusesp)) { - ShowDebug("run_script: bonus2 bSkillUseSP reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillusesp), type2, val); + case SP_SP_GAIN_RACE_ATTACK: + if(sd->state.lr_flag != 2) + sd->sp_gain_race_attack[type2] = cap_value(sd->sp_gain_race_attack[type2] + val, 0, INT16_MAX); + break; + case SP_HP_GAIN_RACE_ATTACK: + if(sd->state.lr_flag != 2) + sd->hp_gain_race_attack[type2] = cap_value(sd->hp_gain_race_attack[type2] + val, 0, INT16_MAX); + break; + case SP_SKILL_USE_SP_RATE: //bonus2 bSkillUseSPrate,n,x; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillusesprate), i, sd->skillusesprate[i].id == 0 || sd->skillusesprate[i].id == type2); + if (i == ARRAYLENGTH(sd->skillusesprate)) { + ShowDebug("script->run: bonus2 bSkillUseSPrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillusesprate), type2, val); + break; + } + if (sd->skillusesprate[i].id == type2) + sd->skillusesprate[i].val += val; + else { + sd->skillusesprate[i].id = type2; + sd->skillusesprate[i].val = val; + } + break; + case SP_SKILL_COOLDOWN: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcooldown)) { + ShowDebug("script->run: bonus2 bSkillCoolDown reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillcooldown), type2, val); + break; + } + if (sd->skillcooldown[i].id == type2) + sd->skillcooldown[i].val += val; + else { + sd->skillcooldown[i].id = type2; + sd->skillcooldown[i].val = val; + } + break; + case SP_SKILL_FIXEDCAST: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillfixcast)) { + ShowDebug("script->run: bonus2 bSkillFixedCast reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillfixcast), type2, val); + break; + } + if (sd->skillfixcast[i].id == type2) + sd->skillfixcast[i].val += val; + else { + sd->skillfixcast[i].id = type2; + sd->skillfixcast[i].val = val; + } + break; + case SP_SKILL_VARIABLECAST: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillvarcast)) { + ShowDebug("script->run: bonus2 bSkillVariableCast reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillvarcast), type2, val); + break; + } + if (sd->skillvarcast[i].id == type2) + sd->skillvarcast[i].val += val; + else { + sd->skillvarcast[i].id = type2; + sd->skillvarcast[i].val = val; + } + break; + #ifdef RENEWAL_CAST + case SP_VARCASTRATE: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcast)) { + ShowDebug("script->run: bonus2 bVariableCastrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillcast), type2, val); + break; + } + if(sd->skillcast[i].id == type2) + sd->skillcast[i].val -= val; + else { + sd->skillcast[i].id = type2; + sd->skillcast[i].val -= val; + } + break; + #endif + case SP_SKILL_USE_SP: //bonus2 bSkillUseSP,n,x; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2); + if (i == ARRAYLENGTH(sd->skillusesp)) { + ShowDebug("script->run: bonus2 bSkillUseSP reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillusesp), type2, val); + break; + } + if (sd->skillusesp[i].id == type2) + sd->skillusesp[i].val += val; + else { + sd->skillusesp[i].id = type2; + sd->skillusesp[i].val = val; + } + break; + case SP_ADD_MONSTER_DROP_CHAINITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, 1<<type2, 10000); + break; + default: + ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); break; - } - if (sd->skillusesp[i].id == type2) - sd->skillusesp[i].val += val; - else { - sd->skillusesp[i].id = type2; - sd->skillusesp[i].val = val; - } - break; - default: - ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); - break; } return 0; } @@ -3248,161 +3327,185 @@ int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) nullpo_ret(sd); switch(type){ - case SP_ADD_MONSTER_DROP_ITEM: - if(sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, 1<<type3, val); - break; - case SP_ADD_CLASS_DROP_ITEM: - if(sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val); - break; - case SP_AUTOSPELL: - if(sd->state.lr_flag != 2) - { - int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. - target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), - target?-type2:type2, type3, val, 0, current_equip_card_id); - } - break; - case SP_AUTOSPELL_WHENHIT: - if(sd->state.lr_flag != 2) - { - int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. - target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), - target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, current_equip_card_id); - } - break; - case SP_SP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].per += type3; - sd->right_weapon.sp_drain[RC_NONBOSS].type = val; - sd->right_weapon.sp_drain[RC_BOSS].rate += type2; - sd->right_weapon.sp_drain[RC_BOSS].per += type3; - sd->right_weapon.sp_drain[RC_BOSS].type = val; - - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].per += type3; - sd->left_weapon.sp_drain[RC_NONBOSS].type = val; - sd->left_weapon.sp_drain[RC_BOSS].rate += type2; - sd->left_weapon.sp_drain[RC_BOSS].per += type3; - sd->left_weapon.sp_drain[RC_BOSS].type = val; - } - break; - case SP_HP_DRAIN_RATE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[type2].rate += type3; - sd->right_weapon.hp_drain[type2].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[type2].rate += type3; - sd->left_weapon.hp_drain[type2].per += val; - } - break; - case SP_SP_DRAIN_RATE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[type2].rate += type3; - sd->right_weapon.sp_drain[type2].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[type2].rate += type3; - sd->left_weapon.sp_drain[type2].per += val; - } - break; - case SP_ADD_MONSTER_DROP_ITEMGROUP: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, type2, 1<<type3, val); - break; + case SP_ADD_MONSTER_DROP_ITEM: + if(sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, 1<<type3, val); + break; + case SP_ADD_CLASS_DROP_ITEM: + if(sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val); + break; + case SP_AUTOSPELL: + if(sd->state.lr_flag != 2) + { + int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. + target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), + target?-type2:type2, type3, val, 0, status->current_equip_card_id); + } + break; + case SP_AUTOSPELL_WHENHIT: + if(sd->state.lr_flag != 2) + { + int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. + target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), + target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, status->current_equip_card_id); + } + break; + case SP_SP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].per += type3; + sd->right_weapon.sp_drain[RC_NONBOSS].type = val; + sd->right_weapon.sp_drain[RC_BOSS].rate += type2; + sd->right_weapon.sp_drain[RC_BOSS].per += type3; + sd->right_weapon.sp_drain[RC_BOSS].type = val; - case SP_ADDEFF: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2); + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].per += type3; + sd->left_weapon.sp_drain[RC_NONBOSS].type = val; + sd->left_weapon.sp_drain[RC_BOSS].rate += type2; + sd->left_weapon.sp_drain[RC_BOSS].per += type3; + sd->left_weapon.sp_drain[RC_BOSS].type = val; + } + break; + case SP_HP_DRAIN_RATE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[type2].rate += type3; + sd->right_weapon.hp_drain[type2].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[type2].rate += type3; + sd->left_weapon.hp_drain[type2].per += val; + } + break; + case SP_SP_DRAIN_RATE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[type2].rate += type3; + sd->right_weapon.sp_drain[type2].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[type2].rate += type3; + sd->left_weapon.sp_drain[type2].per += val; + } + break; + case SP_ADDEFF: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val); break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val); - break; - case SP_ADDEFF_WHENHIT: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2); + case SP_ADDEFF_WHENHIT: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag != 2) + pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val); break; - } - if(sd->state.lr_flag != 2) - pc_bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val); - break; - case SP_ADDEFF_ONSKILL: - if( type3 > SC_MAX ) { - ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3); + case SP_ADDEFF_ONSKILL: + if( type3 > SC_MAX ) { + ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3); + break; + } + if( sd->state.lr_flag != 2 ) + pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET); break; - } - if( sd->state.lr_flag != 2 ) - pc_bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET); - break; - case SP_ADDELE: - if (type2 > ELE_MAX) { - ShowWarning("pc_bonus3 (SP_ADDELE): element %d is out of range.\n", type2); + case SP_ADDELE: + if (type2 > ELE_MAX) { + ShowWarning("pc_bonus3 (SP_ADDELE): element %d is out of range.\n", type2); + break; + } + if (sd->state.lr_flag != 2) + pc_bonus_addele(sd, (unsigned char)type2, type3, val); break; - } - if (sd->state.lr_flag != 2) - pc_bonus_addele(sd, (unsigned char)type2, type3, val); - break; - case SP_SUBELE: - if (type2 > ELE_MAX) { - ShowWarning("pc_bonus3 (SP_SUBELE): element %d is out of range.\n", type2); + case SP_SUBELE: + if (type2 > ELE_MAX) { + ShowWarning("pc_bonus3 (SP_SUBELE): element %d is out of range.\n", type2); + break; + } + if (sd->state.lr_flag != 2) + pc_bonus_subele(sd, (unsigned char)type2, type3, val); + break; + case SP_SP_VANISH_RATE: + if(sd->state.lr_flag != 2) { + sd->bonus.sp_vanish_rate += type2; + sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per,type3); + sd->bonus.sp_vanish_trigger=val; + } break; - } - if (sd->state.lr_flag != 2) - pc_bonus_subele(sd, (unsigned char)type2, type3, val); - break; - default: - ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); - break; + default: + ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); + break; } return 0; } -int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4,int val) -{ +int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4,int val) { nullpo_ret(sd); - switch(type){ + switch(type) { case SP_AUTOSPELL: if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, 0, current_equip_card_id); + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, 0, status->current_equip_card_id); break; case SP_AUTOSPELL_WHENHIT: if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, BF_NORMAL|BF_SKILL, current_equip_card_id); + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, BF_NORMAL|BF_SKILL, status->current_equip_card_id); break; case SP_AUTOSPELL_ONSKILL: - if(sd->state.lr_flag != 2) - { + if(sd->state.lr_flag != 2) { int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, target?-type3:type3, type4, val, current_equip_card_id); + pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, target?-type3:type3, type4, val, status->current_equip_card_id); } break; case SP_ADDEFF_ONSKILL: if( type2 > SC_MAX ) { - ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type2); + ShowWarning("pc_bonus4 (Add Effect on skill): %d is not supported.\n", type2); break; } if( sd->state.lr_flag != 2 ) - pc_bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, type4, type2, val); + pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, type4, type2, val); + break; + + case SP_SET_DEF_RACE: //bonus4 bSetDefRace,n,x,r,y; + if( type2 > RC_MAX ) { + ShowWarning("pc_bonus4 (DEF_SET): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->def_set_race[type2].rate = type3; + sd->def_set_race[type2].tick = type4; + sd->def_set_race[type2].value = val; + break; + + case SP_SET_MDEF_RACE: //bonus4 bSetMDefRace,n,x,r,y; + if( type2 > RC_MAX ) { + ShowWarning("pc_bonus4 (MDEF_SET): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->mdef_set_race[type2].rate = type3; + sd->mdef_set_race[type2].tick = type4; + sd->mdef_set_race[type2].value = val; break; default: @@ -3413,29 +3516,28 @@ int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4 return 0; } -int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val) -{ +int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val) { nullpo_ret(sd); switch(type){ - case SP_AUTOSPELL: - if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); - break; + case SP_AUTOSPELL: + if(sd->state.lr_flag != 2) + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, status->current_equip_card_id); + break; - case SP_AUTOSPELL_WHENHIT: - if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); - break; + case SP_AUTOSPELL_WHENHIT: + if(sd->state.lr_flag != 2) + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, status->current_equip_card_id); + break; - case SP_AUTOSPELL_ONSKILL: - if(sd->state.lr_flag != 2) - pc_bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, (val&1?-type3:type3), (val&2?-type4:type4), type5, current_equip_card_id); - break; + case SP_AUTOSPELL_ONSKILL: + if(sd->state.lr_flag != 2) + pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, (val&1?-type3:type3), (val&2?-type4:type4), type5, status->current_equip_card_id); + break; - default: - ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val); - break; + default: + ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val); + break; } return 0; @@ -3452,7 +3554,7 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { uint16 index = 0; nullpo_ret(sd); - if( !(index = skill->get_index(id)) || skill_db[index].name == NULL) { + if( !(index = skill->get_index(id)) || skill->db[index].name == NULL) { ShowError("pc_skill: Skill with id %d does not exist in the skill database\n", id); return 0; } @@ -3475,8 +3577,8 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { clif->deleteskill(sd,id); } else clif->addskill(sd,id); - if( !skill_db[index].inf ) //Only recalculate for passive skills. - status_calc_pc(sd, 0); + if( !skill->db[index].inf ) //Only recalculate for passive skills. + status_calc_pc(sd, SCO_NONE); break; case 1: //Item bonus skill. if( sd->status.skill[index].id == id ) { @@ -3509,8 +3611,8 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { clif->deleteskill(sd,id); } else clif->addskill(sd,id); - if( !skill_db[index].inf ) //Only recalculate for passive skills. - status_calc_pc(sd, 0); + if( !skill->db[index].inf ) //Only recalculate for passive skills. + status_calc_pc(sd, SCO_NONE); break; default: //Unknown flag? return 0; @@ -3579,13 +3681,12 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) /*========================================== * Update buying value by skills *------------------------------------------*/ -int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) -{ - int skill,val = orig_value,rate1 = 0,rate2 = 0; - if((skill=pc->checkskill(sd,MC_DISCOUNT))>0) // merchant discount - rate1 = 5+skill*2-((skill==10)? 1:0); - if((skill=pc->checkskill(sd,RG_COMPULSION))>0) // rogue discount - rate2 = 5+skill*4; +int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) { + int skill_lv,val = orig_value,rate1 = 0,rate2 = 0; + if((skill_lv=pc->checkskill(sd,MC_DISCOUNT))>0) // merchant discount + rate1 = 5+skill_lv*2-((skill_lv==10)? 1:0); + if((skill_lv=pc->checkskill(sd,RG_COMPULSION))>0) // rogue discount + rate2 = 5+skill_lv*4; if(rate1 < rate2) rate1 = rate2; if(rate1) val = (int)((double)orig_value*(double)(100-rate1)/100.); @@ -3598,11 +3699,10 @@ int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) /*========================================== * Update selling value by skills *------------------------------------------*/ -int pc_modifysellvalue(struct map_session_data *sd,int orig_value) -{ - int skill,val = orig_value,rate = 0; - if((skill=pc->checkskill(sd,MC_OVERCHARGE))>0) //OverCharge - rate = 5+skill*2-((skill==10)? 1:0); +int pc_modifysellvalue(struct map_session_data *sd,int orig_value) { + int skill_lv,val = orig_value,rate = 0; + if((skill_lv=pc->checkskill(sd,MC_OVERCHARGE))>0) //OverCharge + rate = 5+skill_lv*2-((skill_lv==10)? 1:0); if(rate) val = (int)((double)orig_value*(double)(100+rate)/100.); if(val < 0) val = 0; @@ -3625,9 +3725,9 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount) if(amount > MAX_AMOUNT) return ADDITEM_OVERAMOUNT; - data = itemdb_search(nameid); + data = itemdb->search(nameid); - if(!itemdb_isstackable2(data)) + if(!itemdb->isstackable2(data)) return ADDITEM_NEW; if( data->stack.inventory && amount > data->stack.amount ) @@ -3688,7 +3788,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,strlen(output)); } return 0; @@ -3723,14 +3823,14 @@ int pc_paycash(struct map_session_data *sd, int price, int points) return -1; } - pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints-cash); - pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints-points); + pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints-cash); + pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints-points); if( battle_config.cashshop_show_points ) { char output[128]; sprintf(output, msg_txt(504), points, cash, sd->kafraPoints, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return cash+points; } @@ -3750,12 +3850,12 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) cash = MAX_ZENY-sd->cashPoints; } - pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints+cash); + pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints+cash); if( battle_config.cashshop_show_points ) { sprintf(output, msg_txt(505), cash, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return cash; } @@ -3773,12 +3873,12 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) points = MAX_ZENY-sd->kafraPoints; } - pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints+points); + pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints+points); if( battle_config.cashshop_show_points ) { sprintf(output, msg_txt(506), points, sd->kafraPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return points; } @@ -3816,22 +3916,29 @@ 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,strlen(output)); } return 0; } -/*========================================== - * Searching a specified itemid in inventory and return his stored index - *------------------------------------------*/ -int pc_search_inventory(struct map_session_data *sd,int item_id) -{ +/** + * Searches for the specified item ID in inventory and return its inventory index. + * + * If the item is found, the returned value is guaranteed to be a valid index + * (non-negative, smaller than MAX_INVENTORY). + * + * @param sd Character to search on. + * @param item_id The item ID to search. + * @return the inventory index of the first instance of the requested item. + * @retval INDEX_NOT_FOUND if the item wasn't found. + */ +int pc_search_inventory(struct map_session_data *sd, int item_id) { int i; - nullpo_retr(-1, sd); + nullpo_retr(INDEX_NOT_FOUND, sd); ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == item_id && (sd->status.inventory[i].amount > 0 || item_id == 0) ); - return ( i < MAX_INVENTORY ) ? i : -1; + return ( i < MAX_INVENTORY ) ? i : INDEX_NOT_FOUND; } /*========================================== @@ -3840,11 +3947,11 @@ int pc_search_inventory(struct map_session_data *sd,int item_id) 0 = success 1 = invalid itemid not found or negative amount 2 = overweight - 3 = ? + 3 = ? 4 = no free place found 5 = max amount reached - 6 = ? - 7 = stack limitation + 6 = ? + 7 = stack limitation *------------------------------------------*/ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type) { @@ -3860,7 +3967,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if( amount > MAX_AMOUNT ) return 5; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.inventory && amount > data->stack.amount ) {// item stack limitation @@ -3871,14 +3978,37 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if(sd->weight + w > sd->max_weight) return 2; + if( item_data->bound ) { + switch( (enum e_item_bound_type)item_data->bound ) { + case IBT_CHARACTER: + case IBT_ACCOUNT: + break; /* no restrictions */ + case IBT_PARTY: + if( !sd->status.party_id ) { + ShowError("pc_additem: can't add party_bound item to character without party!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + case IBT_GUILD: + if( !sd->status.guild_id ) { + ShowError("pc_additem: can't add guild_bound item to character without guild!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + } + } + i = MAX_INVENTORY; - if( itemdb_isstackable2(data) && item_data->expire_time == 0 ) - { // Stackable | Non Rental - for( i = 0; i < MAX_INVENTORY; i++ ) - { - if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) - { + // Stackable | Non Rental + if( itemdb->isstackable2(data) && item_data->expire_time == 0 ) { + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid == item_data->nameid && + sd->status.inventory[i].bound == item_data->bound && + sd->status.inventory[i].expire_time == 0 && + memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) { if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) ) return 5; sd->status.inventory[i].amount += amount; @@ -3888,25 +4018,26 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l } } - if( i >= MAX_INVENTORY ) - { + if ( i >= MAX_INVENTORY ) { i = pc->search_inventory(sd,0); - if( i < 0 ) + if (i == INDEX_NOT_FOUND) return 4; memcpy(&sd->status.inventory[i], item_data, sizeof(sd->status.inventory[0])); - // clear equips field first, just in case + // clear equip and favorite fields first, just in case if( item_data->equip ) sd->status.inventory[i].equip = 0; + if( item_data->favorite ) + sd->status.inventory[i].favorite = 0; sd->status.inventory[i].amount = amount; 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 + + if( !itemdb->isstackable2(data) && !item_data->unique_id ) + 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; @@ -3918,8 +4049,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l /* rental item check */ if( item_data->expire_time ) { if( time(NULL) > item_data->expire_time ) { - clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 1, 0, LOG_TYPE_OTHER); + pc->rental_expire(sd,i); } else { int seconds = (int)( item_data->expire_time - time(NULL) ); clif->rental_time(sd->fd, sd->status.inventory[i].nameid, seconds); @@ -3989,8 +4119,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) ) return 0; - if( map[sd->bl.m].flag.nodrop ) - { + if( map->list[sd->bl.m].flag.nodrop ) { clif->message (sd->fd, msg_txt(271)); return 0; //Can't drop items in nodrop mapflag maps. } @@ -4001,7 +4130,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) return 0; } - if (!iMap->addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2)) + if (!map->addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2)) return 0; pc->delitem(sd, n, amount, 1, 0, LOG_TYPE_PICKDROP_PLAYER); @@ -4018,7 +4147,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) { int flag=0; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); struct map_session_data *first_sd = NULL,*second_sd = NULL,*third_sd = NULL; struct party_data *p=NULL; @@ -4031,9 +4160,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) if (sd->status.party_id) p = party->search(sd->status.party_id); - if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) - { - first_sd = iMap->charid2sd(fitem->first_get_charid); + if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) { + first_sd = map->charid2sd(fitem->first_get_charid); if(DIFF_TICK(tick,fitem->first_get_tick) < 0) { if (!(p && p->party.item&1 && first_sd && first_sd->status.party_id == sd->status.party_id @@ -4041,9 +4169,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) return 0; } else - if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) - { - second_sd = iMap->charid2sd(fitem->second_get_charid); + if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) { + second_sd = map->charid2sd(fitem->second_get_charid); if(DIFF_TICK(tick, fitem->second_get_tick) < 0) { if(!(p && p->party.item&1 && ((first_sd && first_sd->status.party_id == sd->status.party_id) || @@ -4052,9 +4179,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) return 0; } else - if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id) - { - third_sd = iMap->charid2sd(fitem->third_get_charid); + if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id) { + third_sd = map->charid2sd(fitem->third_get_charid); if(DIFF_TICK(tick,fitem->third_get_tick) < 0) { if(!(p && p->party.item&1 && ((first_sd && first_sd->status.party_id == sd->status.party_id) || @@ -4076,7 +4202,7 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) //Display pickup animation. pc_stop_attack(sd); clif->takeitem(&sd->bl,&fitem->bl); - iMap->clearflooritem(&fitem->bl); + map->clearflooritem(&fitem->bl); return 1; } @@ -4104,96 +4230,97 @@ 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) ) { - clif->msgtable(sd->fd,664); + 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. } - switch( nameid ) //@TODO, lot oh harcoded nameid here - { - case 605: // Anodyne - if( map_flag_gvg(sd->bl.m) ) + if (sd->state.storage_flag && item->type != IT_CASH) { + clif->colormes(sd->fd, COLOR_RED, msg_txt(1475)); + return 0; // You cannot use this item while storage is open. + } + + 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; - case 606: + case ITEMID_ALOEBERA: if( pc_issit(sd) ) return 0; break; - case 601: // Fly Wing - case 12212: // Giant Fly Wing - if( map[sd->bl.m].flag.noteleport || map_flag_gvg(sd->bl.m) ) - { + 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); return 0; } - case 602: // ButterFly Wing - case 14527: // Dungeon Teleport Scroll - case 14581: // Dungeon Teleport Scroll - case 14582: // Yellow Butterfly Wing - case 14583: // Green Butterfly Wing - case 14584: // Red Butterfly Wing - case 14585: // Blue Butterfly Wing - case 14591: // Siege Teleport Scroll - if( sd->duel_group && !battle_config.duel_allow_teleport ) - { - clif->message(sd->fd, msg_txt(663)); + case ITEMID_WING_OF_BUTTERFLY: + case ITEMID_DUN_TELE_SCROLL1: + case ITEMID_DUN_TELE_SCROLL2: + case ITEMID_WOB_RUNE: // Yellow Butterfly Wing + case ITEMID_WOB_SCHWALTZ: // Green Butterfly Wing + case ITEMID_WOB_RACHEL: // Red Butterfly Wing + case ITEMID_WOB_LOCAL: // Blue Butterfly Wing + case ITEMID_SIEGE_TELEPORT_SCROLL: + if( sd->duel_group && !battle_config.duel_allow_teleport ) { + clif->message(sd->fd, msg_txt(863)); // "Duel: Can't use this item in duel." return 0; } - if( nameid != 601 && nameid != 12212 && map[sd->bl.m].flag.noreturn ) + if( nameid != ITEMID_WING_OF_FLY && nameid != ITEMID_GIANT_FLY_WING && map->list[sd->bl.m].flag.noreturn ) return 0; break; - case 604: // Dead Branch - case 12024: // Red Pouch - case 12103: // Bloody Branch - case 12109: // Poring Box - if( map[sd->bl.m].flag.nobranch || map_flag_gvg(sd->bl.m) ) + case ITEMID_BRANCH_OF_DEAD_TREE: + case ITEMID_RED_POUCH_OF_SURPRISE: + case ITEMID_BLOODY_DEAD_BRANCH: + case ITEMID_PORING_BOX: + if( map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m) ) return 0; break; - case 12210: // Bubble Gum - case 12264: // Comp Bubble Gum + case ITEMID_BUBBLE_GUM: + case ITEMID_COMP_BUBBLE_GUM: if( sd->sc.data[SC_CASH_RECEIVEITEM] ) return 0; break; - case 12208: // Battle Manual - case 12263: // Comp Battle Manual - case 12312: // Thick Battle Manual - case 12705: // Noble Nameplate - case 14532: // Battle_Manual25 - case 14533: // Battle_Manual100 - case 14545: // Battle_Manual300 + case ITEMID_BATTLE_MANUAL: + case ITEMID_COMP_BATTLE_MANUAL: + case ITEMID_THICK_MANUAL50: + case ITEMID_NOBLE_NAMEPLATE: + case ITEMID_BATTLE_MANUAL25: + case ITEMIDBATTLE_MANUAL100: + case ITEMID_BATTLE_MANUAL_X3: if( sd->sc.data[SC_CASH_PLUSEXP] ) return 0; break; - case 14592: // JOB_Battle_Manual + case ITEMID_JOB_MANUAL50: if( sd->sc.data[SC_CASH_PLUSONLYJOBEXP] ) return 0; break; // Mercenary Items - - case 12184: // Mercenary's Red Potion - case 12185: // Mercenary's Blue Potion - case 12241: // Mercenary's Concentration Potion - case 12242: // Mercenary's Awakening Potion - case 12243: // Mercenary's Berserk Potion + case ITEMID_MERCENARY_RED_POTION: + case ITEMID_MERCENARY_BLUE_POTION: + case ITEMID_M_CENTER_POTION: + case ITEMID_M_AWAKENING_POTION: + case ITEMID_M_BERSERK_POTION: if( sd->md == NULL || sd->md->db == NULL ) return 0; - if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->md->sc.data[SC__BLOODYLUST]) + if (sd->md->sc.data[SC_BERSERK]) return 0; - if( nameid == 12242 && sd->md->db->lv < 40 ) + if( nameid == ITEMID_M_AWAKENING_POTION && sd->md->db->lv < 40 ) return 0; - if( nameid == 12243 && sd->md->db->lv < 80 ) + if( nameid == ITEMID_M_BERSERK_POTION && sd->md->db->lv < 80 ) return 0; break; - case 12213: //Neuralizer - if( !map[sd->bl.m].flag.reset ) + case ITEMID_NEURALIZER: + if( !map->list[sd->bl.m].flag.reset ) return 0; break; } - if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL ) - return 0; // Mercenary Scrolls + if( nameid >= ITEMID_BOW_MERCENARY_SCROLL1 && nameid <= ITEMID_SPEARMERCENARY_SCROLL10 && sd->md != NULL ) // Mercenary Scrolls + return 0; /** * Only Rune Knights may use runes @@ -4206,17 +4333,30 @@ int pc_isUseitem(struct map_session_data *sd,int n) 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->fd,ITEM_CANT_OBTAIN_WEIGHT); + return 0; + } + if( !pc->inventoryblank(sd) ) { + clif->colormes(sd->fd,COLOR_RED,msg_txt(1477)); + return 0; + } + } + //Gender check 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 < (unsigned int)item->elv){ + clif->msg(sd, 0x6EE); return 0; + } -#ifdef RENEWAL - if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) + if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax){ + clif->msg(sd, 0x6EE); return 0; -#endif + } //Not equipable by class. [Skotlex] if (!( @@ -4224,20 +4364,29 @@ int pc_isUseitem(struct map_session_data *sd,int n) (item->class_base[sd->class_&JOBL_2_1?1:(sd->class_&JOBL_2_2?2:0)]) )) return 0; - //Not usable by upper class. [Inkfish] + + //Not usable by upper class. [Haru] while( 1 ) { - if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; - if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; - if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; - if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; + // Normal classes (no upper, no baby, no third classes) + if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; +#ifdef RENEWAL + // Upper classes (no third classes) + if( item->class_upper&ITEMUPPER_UPPER && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) 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; +#endif + // Baby classes (no third classes) + if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) 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; + // Upper third classes + if( item->class_upper&ITEMUPPER_THURDUPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break; + // Baby third classes + if( item->class_upper&ITEMUPPER_THIRDBABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break; return 0; } - //Dead Branch & Bloody Branch & Porings Box - // FIXME: outdated, use constants or database - if( nameid == 604 || nameid == 12103 || nameid == 12109 ) - logs->branch(sd); - return 1; } @@ -4247,11 +4396,10 @@ int pc_isUseitem(struct map_session_data *sd,int n) * 0 = fail * 1 = success *------------------------------------------*/ -int pc_useitem(struct map_session_data *sd,int n) -{ - unsigned int tick = iTimer->gettick(); +int pc_useitem(struct map_session_data *sd,int n) { + int64 tick = timer->gettick(); int amount, nameid, i; - struct script_code *script; + struct script_code *item_script; nullpo_ret(sd); @@ -4266,7 +4414,7 @@ int pc_useitem(struct map_session_data *sd,int n) if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 ) return 0; - if( !pc_isUseitem(sd,n) ) + if( !pc->isUseitem(sd,n) ) return 0; // Store information for later use before it is lost (via pc->delitem) [Paradox924X] @@ -4275,15 +4423,20 @@ 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__BLOODYLUST] || + sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) || sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_HIDING] || sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__INVISIBILITY] || sd->sc.data[SC__MANHOLE] || sd->sc.data[SC_KG_KAGEHUMI] || 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; @@ -4305,18 +4458,17 @@ int pc_useitem(struct map_session_data *sd,int n) //perform a skill-use check before going through. [Skotlex] //resurrection was picked as testing skill, as a non-offensive, generic skill, it will do. //FIXME: Is this really needed here? It'll be checked in unit.c after all and this prevents skill items using when silenced [Inkfish] - if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) ) + 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 ) { - int i; 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 = DIFF_TICK(sd->item_delay[i].tick, tick)/1000; + int e_tick = (int)(DIFF_TICK(sd->item_delay[i].tick, tick)/1000); clif->msgtable_num(sd->fd, 0x746, e_tick + 1); // [%d] seconds left until you can use return 0; // Delay has not expired yet } @@ -4337,10 +4489,11 @@ int pc_useitem(struct map_session_data *sd,int n) } } - /* on restricted maps the item is consumed but the effect is not used */ - for(i = 0; i < map[sd->bl.m].zone->disabled_items_count; i++) { - if( map[sd->bl.m].zone->disabled_items[i] == nameid ) { - if( battle_config.item_restricted_consumption_type ) { + /* 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 + if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) { clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true); pc->delitem(sd,n,1,1,0,LOG_TYPE_CONSUME); } @@ -4348,13 +4501,17 @@ int pc_useitem(struct map_session_data *sd,int n) } } + //Dead Branch & Bloody Branch & Porings Box + if( nameid == ITEMID_BRANCH_OF_DEAD_TREE || nameid == ITEMID_BLOODY_DEAD_BRANCH || nameid == ITEMID_PORING_BOX ) + logs->branch(sd); + sd->itemid = sd->status.inventory[n].nameid; sd->itemindex = n; if(sd->catch_target_class != -1) //Abort pet catching. sd->catch_target_class = -1; amount = sd->status.inventory[n].amount; - script = sd->inventory_data[n]->script; + item_script = sd->inventory_data[n]->script; //Check if the item is to be consumed immediately [Skotlex] if( sd->inventory_data[n]->flag.delay_consume ) clif->useitemack(sd,n,amount,true); @@ -4368,18 +4525,23 @@ 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)) { - potion_flag = 2; // Famous player's potions have 50% more efficiency + 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) - potion_flag = 3; //Even more effective potions. + script->potion_flag = 3; //Even more effective potions. } //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; - - run_script(script,0,sd->bl.id,fake_nd->bl.id); - potion_flag = 0; + + script->current_item_id = nameid; + + script->run(item_script,0,sd->bl.id,npc->fake_nd->bl.id); + + script->current_item_id = 0; + script->potion_flag = 0; + return 1; } @@ -4399,35 +4561,35 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun if(item_data->nameid <= 0 || amount <= 0) return 1; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.cart && amount > data->stack.amount ) {// item stack limitation return 1; } - if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) ) - { // Check item trade restrictions [Skotlex] + 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 [Skotlex] clif->message (sd->fd, msg_txt(264)); - return 1; + return 1;/* TODO: there is no official response to this? */ } if( (w = data->weight*amount) + sd->cart_weight > sd->cart_weight_max ) return 1; i = MAX_CART; - if( itemdb_isstackable2(data) && !item_data->expire_time ) + if( itemdb->isstackable2(data) && !item_data->expire_time ) { ARR_FIND( 0, MAX_CART, i, - sd->status.cart[i].nameid == item_data->nameid && - sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && + sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound && + sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] ); }; if( i < MAX_CART ) {// item already in cart, stack it if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) ) - return 1; // no room + return 2; // no room sd->status.cart[i].amount+=amount; clif->cart_additem(sd,i,amount,0); @@ -4436,7 +4598,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun {// item not stackable or not present, add it ARR_FIND( 0, MAX_CART, i, sd->status.cart[i].nameid == 0 ); if( i == MAX_CART ) - return 1; // no room + return 2; // no room memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0])); sd->status.cart[i].amount=amount; @@ -4462,7 +4624,7 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_ struct item_data * data; nullpo_retr(1, sd); - if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb_exists(sd->status.cart[n].nameid)) ) + if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb->exists(sd->status.cart[n].nameid)) ) return 1; logs->pick_pc(sd, log_type, -amount, &sd->status.cart[n],data); @@ -4490,6 +4652,7 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_ int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) { struct item *item_data; + int flag; nullpo_ret(sd); @@ -4501,10 +4664,10 @@ int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending ) return 1; - if( pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE) == 0 ) + if( (flag = pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0 ) return pc->delitem(sd,idx,amount,0,5,LOG_TYPE_NONE); - return 1; + return flag; } /*========================================== @@ -4546,13 +4709,45 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) if(item_data->nameid==0 || amount < 1 || item_data->amount<amount || sd->state.vending ) return 1; + if((flag = pc->additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0) return pc->cart_delitem(sd,idx,amount,0,LOG_TYPE_NONE); - clif->additem(sd,0,0,flag); - return 1; + return flag; +} +void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) { + int i; + + switch( type ) { + /* both restricted to inventory */ + case IBT_PARTY: + case IBT_CHARACTER: + for( i = 0; i < MAX_INVENTORY; i++ ){ + if( sd->status.inventory[i].bound == type ) { + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,LOG_TYPE_OTHER); + } + } + break; + case IBT_ACCOUNT: + ShowError("Helllo! You reached pc_bound_clear for IBT_ACCOUNT, unfortunately no scenario was expected for this!\n"); + break; + case IBT_GUILD: { + struct guild_storage *gstor = gstorage->id2storage(sd->status.guild_id); + + for( i = 0; i < MAX_INVENTORY; i++ ){ + if(sd->status.inventory[i].bound == type) { + if( gstor ) + gstorage->additem(sd,gstor,&sd->status.inventory[i],sd->status.inventory[i].amount); + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,gstor?LOG_TYPE_GSTORAGE:LOG_TYPE_OTHER); + } + } + if( gstor ) + gstorage->close(sd); + } + break; + } + } - /*========================================== * Display item stolen msg to player sd *------------------------------------------*/ @@ -4567,7 +4762,7 @@ int pc_show_steal(struct block_list *bl,va_list ap) sd=va_arg(ap,struct map_session_data *); itemid=va_arg(ap,int); - if((item=itemdb_exists(itemid))==NULL) + if((item=itemdb->exists(itemid))==NULL) sprintf(output,"%s stole an Unknown Item (id: %i).",sd->status.name, itemid); else sprintf(output,"%s stole %s.",sd->status.name,item->jname); @@ -4598,11 +4793,11 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil if(md->state.steal_flag == UCHAR_MAX || ( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check return 0; - sd_status= status_get_status_data(&sd->bl); - md_status= status_get_status_data(bl); + sd_status= status->get_status_data(&sd->bl); + md_status= status->get_status_data(bl); if( md->master_id || md_status->mode&MD_BOSS || mob_is_treasure(md) || - map[bl->m].flag.nomobloot || // check noloot map flag [Lorky] + map->list[bl->m].flag.nomobloot || // check noloot map flag [Lorky] (battle_config.skill_steal_max_tries && //Reached limit of steal attempts. [Lupus] md->state.steal_flag++ >= battle_config.skill_steal_max_tries) ) { //Can't steal from @@ -4620,7 +4815,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil // Try dropping one item, in the order from first to last possible slot. // Droprate is affected by the skill success rate. for( i = 0; i < MAX_STEAL_DROP; i++ ) - if( md->db->dropitem[i].nameid > 0 && (data = itemdb_exists(md->db->dropitem[i].nameid)) && rnd() % 10000 < md->db->dropitem[i].p * rate/100. ) + if( md->db->dropitem[i].nameid > 0 && (data = itemdb->exists(md->db->dropitem[i].nameid)) && rnd() % 10000 < md->db->dropitem[i].p * rate/100. ) break; if( i == MAX_STEAL_DROP ) return 0; @@ -4629,7 +4824,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.nameid = itemid; tmp_item.amount = 1; - tmp_item.identify = itemdb_isidentified2(data); + tmp_item.identify = itemdb->isidentified2(data); flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER); //TODO: Should we disable stealing when the item you stole couldn't be added to your inventory? Perhaps players will figure out a way to exploit this behaviour otherwise? @@ -4641,7 +4836,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil } if(battle_config.show_steal_in_same_party) - party_foreachsamemap(pc_show_steal,sd,AREA_SIZE,sd,tmp_item.nameid); + party->foreachsamemap(pc->show_steal,sd,AREA_SIZE,sd,tmp_item.nameid); //Logs items, Stolen from mobs [Lupus] logs->pick_mob(md, LOG_TYPE_STEAL, -1, &tmp_item, data); @@ -4651,20 +4846,21 @@ 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 != NULL)?sd->status.name :"GM", 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,0); + intif->broadcast(message, strlen(message)+1, BC_DEFAULT); } return 1; } -/*========================================== - * Stole zeny from bl (mob) - * return - * 0 = fail - * 1 = success - *------------------------------------------*/ -int pc_steal_coin(struct map_session_data *sd,struct block_list *target) -{ - int rate,skill; +/** + * Steals zeny from a monster through the RG_STEALCOIN skill. + * + * @param sd Source character + * @param target Target monster + * + * @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; struct mob_data *md; if(!sd || !target || target->type != BL_MOB) return 0; @@ -4676,16 +4872,14 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) if( mob_is_treasure(md) ) return 0; - // FIXME: This formula is either custom or outdated. - skill = pc->checkskill(sd,RG_STEALCOIN)*10; - rate = skill + (sd->status.base_level - md->level)*3 + sd->battle_status.dex*2 + sd->battle_status.luk*2; - if(rnd()%1000 < rate) - { - int amount = md->level*10 + rnd()%100; + 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] pc->getzeny(sd, amount, LOG_TYPE_STEAL, NULL); md->state.steal_coin_flag = 1; - return 1; + return amount; } return 0; } @@ -4697,13 +4891,13 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) * 1 - Invalid map index. * 2 - Map not in this map-server, and failed to locate alternate map-server. *------------------------------------------*/ -int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype) { +int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int y, clr_type clrtype) { int16 m; nullpo_ret(sd); - if( !mapindex || !mapindex_id2name(mapindex) ) { - ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", mapindex); + if( !map_index || !mapindex_id2name(map_index) || ( m = map->mapindex2mapid(map_index) ) == -1 ) { + ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", map_index); return 1; } @@ -4711,53 +4905,68 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y pc->setstand(sd); pc->setrestartvalue(sd,1); } - m = iMap->mapindex2mapid(mapindex); - if( map[m].flag.src4instance ) { + if( map->list[m].flag.src4instance ) { struct party_data *p; bool stop = false; int i = 0, j = 0; if( sd->instances ) { for( i = 0; i < sd->instances; i++ ) { - ARR_FIND(0, instances[sd->instance[i]].num_map, j, map[instances[sd->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->instance[i]].map[j]].cName); - if( j != instances[sd->instance[i]].num_map ) - break; + if( sd->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->instance[i]].map[j]].custom_name); + if( j != instance->list[sd->instance[i]].num_map ) + break; + } } if( i != sd->instances ) { - m = instances[sd->instance[i]].map[j]; - mapindex = map[m].index; + m = instance->list[sd->instance[i]].map[j]; + map_index = map_id2index(m); stop = true; } } if ( !stop && sd->status.party_id && (p = party->search(sd->status.party_id)) && p->instances ) { for( i = 0; i < p->instances; i++ ) { - ARR_FIND(0, instances[p->instance[i]].num_map, j, map[instances[p->instance[i]].map[j]].instance_src_map == m && !map[instances[p->instance[i]].map[j]].cName); - if( j != instances[p->instance[i]].num_map ) - break; + if( p->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[p->instance[i]].map[j]].custom_name); + if( j != instance->list[p->instance[i]].num_map ) + break; + } } if( i != p->instances ) { - m = instances[p->instance[i]].map[j]; - mapindex = map[m].index; + m = instance->list[p->instance[i]].map[j]; + map_index = map_id2index(m); stop = true; } } if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) { for( i = 0; i < sd->guild->instances; i++ ) { - ARR_FIND(0, instances[sd->guild->instance[i]].num_map, j, map[instances[sd->guild->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->guild->instance[i]].map[j]].cName); - if( j != instances[sd->guild->instance[i]].num_map ) - break; + if( sd->guild->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name); + if( j != instance->list[sd->guild->instance[i]].num_map ) + break; + } } if( i != sd->guild->instances ) { - m = instances[sd->guild->instance[i]].map[j]; - mapindex = map[m].index; - stop = true; + m = instance->list[sd->guild->instance[i]].map[j]; + map_index = map_id2index(m); + //stop = true; Uncomment if adding new checks } } + + /* we hit a instance, if empty we populate the spawn data */ + if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 && + instance->list[map->list[m].instance_id].respawn.x == 0 && + instance->list[map->list[m].instance_id].respawn.y == 0) { + instance->list[map->list[m].instance_id].respawn.map = map_index; + instance->list[map->list[m].instance_id].respawn.x = x; + instance->list[map->list[m].instance_id].respawn.y = y; + } } - sd->state.changemap = (sd->mapindex != mapindex); + sd->state.changemap = (sd->mapindex != map_index); sd->state.warping = 1; + sd->state.workinprogress = 0; if( sd->state.changemap ) { // Misc map-changing settings int i; sd->state.pmap = sd->bl.m; @@ -4765,13 +4974,13 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y for( i = 0; i < sd->queues_count; i++ ) { struct hQueue *queue; if( (queue = script->queue(sd->queues[i])) && queue->onMapChange[0] != '\0' ) { - pc->setregstr(sd, add_str("QMapChangeTo"), map[m].name); - npc_event(sd, queue->onMapChange, 0); + pc->setregstr(sd, script->add_str("QMapChangeTo"), map->list[m].name); + npc->event(sd, queue->onMapChange, 0); } } - if( map[m].cell == (struct mapcell *)0xdeadbeaf ) - iMap->cellfromcache(&map[m]); + if( map->list[m].cell == (struct mapcell *)0xdeadbeaf ) + map->cellfromcache(&map->list[m]); if (sd->sc.count) { // Cancel some map related stuff. if (sd->sc.data[SC_JAILED]) return 1; //You may not get out! @@ -4781,11 +4990,15 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER); status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER); status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER); + status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);//Will later check if this is needed. [Rytech] + status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER); + status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER); + status_change_end(&sd->bl, SC_STEALTHFIELD, INVALID_TIMER); if (sd->sc.data[SC_KNOWLEDGE]) { struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE]; if (sce->timer != INVALID_TIMER) - iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(iTimer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status_change_timer, sd->bl.id, SC_KNOWLEDGE); + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status->change_timer, sd->bl.id, SC_KNOWLEDGE); } status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER); status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER); @@ -4800,76 +5013,75 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y skill->clear_unitgroup(&sd->bl); party->send_dot_remove(sd); //minimap dot fix [Kevin] guild->send_dot_remove(sd); - bg_send_dot_remove(sd); + bg->send_dot_remove(sd); if (sd->regen.state.gc) sd->regen.state.gc = 0; // make sure vending is allowed here - if (sd->state.vending && map[m].flag.novending) { + if (sd->state.vending && map->list[m].flag.novending) { clif->message (sd->fd, msg_txt(276)); // "You can't open a shop on this map" vending->close(sd); } - if( hChSys.local && map[sd->bl.m].channel && idb_exists(map[sd->bl.m].channel->users, sd->status.char_id) ) { - clif->chsys_left(map[sd->bl.m].channel,sd); + if( hChSys.local && map->list[sd->bl.m].channel && idb_exists(map->list[sd->bl.m].channel->users, sd->status.char_id) ) { + clif->chsys_left(map->list[sd->bl.m].channel,sd); } - } if( m < 0 ) { uint32 ip; uint16 port; //if can't find any map-servers, just abort setting position. - if(!sd->mapindex || iMap->mapname2ipport(mapindex,&ip,&port)) + if(!sd->mapindex || map->mapname2ipport(map_index,&ip,&port)) return 2; if (sd->npc_id) - npc_event_dequeue(sd); - npc_script_event(sd, NPCE_LOGOUT); + npc->event_dequeue(sd); + npc->script_event(sd, NPCE_LOGOUT); //remove from map, THEN change x/y coordinates - unit_remove_map_pc(sd,clrtype); - sd->mapindex = mapindex; + unit->remove_map_pc(sd,clrtype); + sd->mapindex = map_index; sd->bl.x=x; sd->bl.y=y; pc->clean_skilltree(sd); - chrif_save(sd,2); - chrif_changemapserver(sd, ip, (short)port); + chrif->save(sd,2); + chrif->changemapserver(sd, ip, (short)port); //Free session data from this map server [Kevin] - unit_free_pc(sd); + unit->free_pc(sd); return 0; } - if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) { - ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(mapindex),x,y); + if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) { + ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(map_index),x,y); x = y = 0; // make it random } if( x == 0 && y == 0 ) {// pick a random walkable cell do { - x=rnd()%(map[m].xs-2)+1; - y=rnd()%(map[m].ys-2)+1; - } while(iMap->getcell(m,x,y,CELL_CHKNOPASS)); + x=rnd()%(map->list[m].xs-2)+1; + y=rnd()%(map->list[m].ys-2)+1; + } while(map->getcell(m,x,y,CELL_CHKNOPASS)); } - if (sd->state.vending && iMap->getcell(m,x,y,CELL_CHKNOVENDING)) { + if (sd->state.vending && map->getcell(m,x,y,CELL_CHKNOVENDING)) { clif->message (sd->fd, msg_txt(204)); // "You can't open a shop on this cell." vending->close(sd); } if(sd->bl.prev != NULL){ - unit_remove_map_pc(sd,clrtype); + unit->remove_map_pc(sd,clrtype); clif->changemap(sd,m,x,y); // [MouseJstr] } else if(sd->state.active) //Tag player for rewarping after map-loading is done. [Skotlex] sd->state.rewarp = 1; - sd->mapindex = mapindex; + sd->mapindex = map_index; sd->bl.m = m; sd->bl.x = sd->ud.to_x = x; sd->bl.y = sd->ud.to_y = y; - if( sd->status.guild_id > 0 && map[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris] + if( sd->status.guild_id > 0 && map->list[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris] struct guild_castle *gc = guild->mapindex2gc(sd->mapindex); if(gc && gc->guild_id == sd->status.guild_id) sd->regen.state.gc = 1; @@ -4895,6 +5107,10 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y sd->md->bl.y = sd->md->ud.to_y = y; sd->md->ud.dir = sd->ud.dir; } + + /* given autotrades have no clients you have to trigger this manually otherwise they get stuck in memory limbo bugreport:7495 */ + if( sd->state.autotrade ) + clif->pLoadEndAck(0,sd); return 0; } @@ -4906,8 +5122,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y * 0 = fail or FIXME success (from pc->setpos) * x(1|2) = fail *------------------------------------------*/ -int pc_randomwarp(struct map_session_data *sd, clr_type type) -{ +int pc_randomwarp(struct map_session_data *sd, clr_type type) { int x,y,i=0; int16 m; @@ -4915,16 +5130,16 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type) m=sd->bl.m; - if (map[sd->bl.m].flag.noteleport) //Teleport forbidden + if (map->list[sd->bl.m].flag.noteleport) //Teleport forbidden return 0; - do{ - x=rnd()%(map[m].xs-2)+1; - y=rnd()%(map[m].ys-2)+1; - }while(iMap->getcell(m,x,y,CELL_CHKNOPASS) && (i++)<1000 ); + do { + x=rnd()%(map->list[m].xs-2)+1; + y=rnd()%(map->list[m].ys-2)+1; + } while( map->getcell(m,x,y,CELL_CHKNOPASS) && (i++) < 1000 ); if (i < 1000) - return pc->setpos(sd,map[sd->bl.m].index,x,y,type); + return pc->setpos(sd,map_id2index(sd->bl.m),x,y,type); return 0; } @@ -4933,14 +5148,13 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type) * Records a memo point at sd's current position * pos - entry to replace, (-1: shift oldest entry out) *------------------------------------------*/ -int pc_memo(struct map_session_data* sd, int pos) -{ - int skill; +int pc_memo(struct map_session_data* sd, int pos) { + int skill_lv; nullpo_ret(sd); // check mapflags - if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { + if( sd->bl.m >= 0 && (map->list[sd->bl.m].flag.nomemo || map->list[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { clif->skill_mapinfomessage(sd, 1); // "Saved point cannot be memorized." return 0; } @@ -4950,12 +5164,12 @@ int pc_memo(struct map_session_data* sd, int pos) return 0; // invalid input // check required skill level - skill = pc->checkskill(sd, AL_WARP); - if( skill < 1 ) { + skill_lv = pc->checkskill(sd, AL_WARP); + if( skill_lv < 1 ) { clif->skill_memomessage(sd,2); // "You haven't learned Warp." return 0; } - if( skill < 2 || skill - 2 < pos ) { + if( skill_lv < 2 || skill_lv - 2 < pos ) { clif->skill_memomessage(sd,1); // "Skill Level is not high enough." return 0; } @@ -5009,14 +5223,14 @@ int pc_checkskill2(struct map_session_data *sd,uint16 index) { ShowError("pc_checkskill: Invalid skill index %d (char_id=%d).\n", index, sd->status.char_id); return 0; } - if( skill_db[index].nameid >= GD_SKILLBASE && skill_db[index].nameid < GD_MAX ) { + if( skill->db[index].nameid >= GD_SKILLBASE && skill->db[index].nameid < GD_MAX ) { struct guild *g; if( sd->status.guild_id>0 && (g=sd->guild)!=NULL) - return guild->checkskill(g,skill_db[index].nameid); + return guild->checkskill(g,skill->db[index].nameid); return 0; } - if(sd->status.skill[index].id == skill_db[index].nameid) + if(sd->status.skill[index].id == skill->db[index].nameid) return (sd->status.skill[index].lv); return 0; @@ -5041,9 +5255,11 @@ int pc_checkallowskill(struct map_session_data *sd) SC_DANCING, SC_GS_GATLINGFEVER, #ifdef RENEWAL + SC_LKCONCENTRATION, SC_EDP, #endif - SC_FEARBREEZE + SC_FEARBREEZE, + SC_EXEEDBREAK, }; const enum sc_type scs_list[] = { SC_AUTOGUARD, @@ -5057,12 +5273,12 @@ int pc_checkallowskill(struct map_session_data *sd) if(!sd->sc.count) return 0; - for (i = 0; i < ARRAYLENGTH(scw_list); i++) - { // Skills requiring specific weapon types + for (i = 0; i < ARRAYLENGTH(scw_list); i++) { + // Skills requiring specific weapon types if( scw_list[i] == SC_DANCING && !battle_config.dancing_weaponswitch_fix ) continue; - if(sd->sc.data[scw_list[i]] && - !pc_check_weapontype(sd,skill->get_weapontype(status_sc2skill(scw_list[i])))) + if( sd->sc.data[scw_list[i]] + && !pc_check_weapontype(sd,skill->get_weapontype(status->sc2skill(scw_list[i])))) status_change_end(&sd->bl, scw_list[i], INVALID_TIMER); } @@ -5091,7 +5307,7 @@ int pc_checkequip(struct map_session_data *sd,int pos) nullpo_retr(-1, sd); for(i=0;i<EQI_MAX;i++){ - if(pos & equip_pos[i]) + if(pos & pc->equip_pos[i]) return sd->equip_index[i]; } @@ -5132,6 +5348,7 @@ int pc_jobid2mapid(unsigned short b_class) case JOB_STAR_GLADIATOR: return MAPID_STAR_GLADIATOR; case JOB_KAGEROU: case JOB_OBORO: return MAPID_KAGEROUOBORO; + case JOB_REBELLION: return MAPID_REBELLION; case JOB_DEATH_KNIGHT: return MAPID_DEATH_KNIGHT; //2-2 Jobs case JOB_CRUSADER: return MAPID_CRUSADER; @@ -5272,6 +5489,7 @@ int pc_mapid2jobid(unsigned short class_, int sex) case MAPID_ASSASSIN: return JOB_ASSASSIN; case MAPID_STAR_GLADIATOR: return JOB_STAR_GLADIATOR; case MAPID_KAGEROUOBORO: return sex?JOB_KAGEROU:JOB_OBORO; + case MAPID_REBELLION: return JOB_REBELLION; case MAPID_DEATH_KNIGHT: return JOB_DEATH_KNIGHT; //2-2 Jobs case MAPID_CRUSADER: return JOB_CRUSADER; @@ -5382,107 +5600,107 @@ int pc_mapid2jobid(unsigned short class_, int sex) const char* job_name(int class_) { switch (class_) { - case JOB_NOVICE: - case JOB_SWORDMAN: - case JOB_MAGE: - case JOB_ARCHER: - case JOB_ACOLYTE: - case JOB_MERCHANT: - case JOB_THIEF: + case JOB_NOVICE: // 550 + case JOB_SWORDMAN: // 551 + case JOB_MAGE: // 552 + case JOB_ARCHER: // 553 + case JOB_ACOLYTE: // 554 + case JOB_MERCHANT: // 555 + case JOB_THIEF: // 556 return msg_txt(550 - JOB_NOVICE+class_); - case JOB_KNIGHT: - case JOB_PRIEST: - case JOB_WIZARD: - case JOB_BLACKSMITH: - case JOB_HUNTER: - case JOB_ASSASSIN: + case JOB_KNIGHT: // 557 + case JOB_PRIEST: // 558 + case JOB_WIZARD: // 559 + case JOB_BLACKSMITH: // 560 + case JOB_HUNTER: // 561 + case JOB_ASSASSIN: // 562 return msg_txt(557 - JOB_KNIGHT+class_); case JOB_KNIGHT2: return msg_txt(557); - case JOB_CRUSADER: - case JOB_MONK: - case JOB_SAGE: - case JOB_ROGUE: - case JOB_ALCHEMIST: - case JOB_BARD: - case JOB_DANCER: + case JOB_CRUSADER: // 563 + case JOB_MONK: // 564 + case JOB_SAGE: // 565 + case JOB_ROGUE: // 566 + case JOB_ALCHEMIST: // 567 + case JOB_BARD: // 568 + case JOB_DANCER: // 569 return msg_txt(563 - JOB_CRUSADER+class_); case JOB_CRUSADER2: return msg_txt(563); - case JOB_WEDDING: - case JOB_SUPER_NOVICE: - case JOB_GUNSLINGER: - case JOB_NINJA: - case JOB_XMAS: + case JOB_WEDDING: // 570 + case JOB_SUPER_NOVICE: // 571 + case JOB_GUNSLINGER: // 572 + case JOB_NINJA: // 573 + case JOB_XMAS: // 574 return msg_txt(570 - JOB_WEDDING+class_); case JOB_SUMMER: return msg_txt(621); - case JOB_NOVICE_HIGH: - case JOB_SWORDMAN_HIGH: - case JOB_MAGE_HIGH: - case JOB_ARCHER_HIGH: - case JOB_ACOLYTE_HIGH: - case JOB_MERCHANT_HIGH: - case JOB_THIEF_HIGH: + case JOB_NOVICE_HIGH: // 575 + case JOB_SWORDMAN_HIGH: // 576 + case JOB_MAGE_HIGH: // 577 + case JOB_ARCHER_HIGH: // 578 + case JOB_ACOLYTE_HIGH: // 579 + case JOB_MERCHANT_HIGH: // 580 + case JOB_THIEF_HIGH: // 581 return msg_txt(575 - JOB_NOVICE_HIGH+class_); - case JOB_LORD_KNIGHT: - case JOB_HIGH_PRIEST: - case JOB_HIGH_WIZARD: - case JOB_WHITESMITH: - case JOB_SNIPER: - case JOB_ASSASSIN_CROSS: + case JOB_LORD_KNIGHT: // 582 + case JOB_HIGH_PRIEST: // 583 + case JOB_HIGH_WIZARD: // 584 + case JOB_WHITESMITH: // 585 + case JOB_SNIPER: // 586 + case JOB_ASSASSIN_CROSS: // 587 return msg_txt(582 - JOB_LORD_KNIGHT+class_); case JOB_LORD_KNIGHT2: return msg_txt(582); - case JOB_PALADIN: - case JOB_CHAMPION: - case JOB_PROFESSOR: - case JOB_STALKER: - case JOB_CREATOR: - case JOB_CLOWN: - case JOB_GYPSY: + case JOB_PALADIN: // 588 + case JOB_CHAMPION: // 589 + case JOB_PROFESSOR: // 590 + case JOB_STALKER: // 591 + case JOB_CREATOR: // 592 + case JOB_CLOWN: // 593 + case JOB_GYPSY: // 594 return msg_txt(588 - JOB_PALADIN + class_); case JOB_PALADIN2: return msg_txt(588); - case JOB_BABY: - case JOB_BABY_SWORDMAN: - case JOB_BABY_MAGE: - case JOB_BABY_ARCHER: - case JOB_BABY_ACOLYTE: - case JOB_BABY_MERCHANT: - case JOB_BABY_THIEF: + case JOB_BABY: // 595 + case JOB_BABY_SWORDMAN: // 596 + case JOB_BABY_MAGE: // 597 + case JOB_BABY_ARCHER: // 598 + case JOB_BABY_ACOLYTE: // 599 + case JOB_BABY_MERCHANT: // 600 + case JOB_BABY_THIEF: // 601 return msg_txt(595 - JOB_BABY + class_); - case JOB_BABY_KNIGHT: - case JOB_BABY_PRIEST: - case JOB_BABY_WIZARD: - case JOB_BABY_BLACKSMITH: - case JOB_BABY_HUNTER: - case JOB_BABY_ASSASSIN: + case JOB_BABY_KNIGHT: // 602 + case JOB_BABY_PRIEST: // 603 + case JOB_BABY_WIZARD: // 604 + case JOB_BABY_BLACKSMITH: // 605 + case JOB_BABY_HUNTER: // 606 + case JOB_BABY_ASSASSIN: // 607 return msg_txt(602 - JOB_BABY_KNIGHT + class_); case JOB_BABY_KNIGHT2: return msg_txt(602); - case JOB_BABY_CRUSADER: - case JOB_BABY_MONK: - case JOB_BABY_SAGE: - case JOB_BABY_ROGUE: - case JOB_BABY_ALCHEMIST: - case JOB_BABY_BARD: - case JOB_BABY_DANCER: + case JOB_BABY_CRUSADER: // 608 + case JOB_BABY_MONK: // 609 + case JOB_BABY_SAGE: // 610 + case JOB_BABY_ROGUE: // 611 + case JOB_BABY_ALCHEMIST: // 612 + case JOB_BABY_BARD: // 613 + case JOB_BABY_DANCER: // 614 return msg_txt(608 - JOB_BABY_CRUSADER + class_); case JOB_BABY_CRUSADER2: @@ -5499,74 +5717,82 @@ const char* job_name(int class_) case JOB_SOUL_LINKER: return msg_txt(618); - case JOB_GANGSI: - case JOB_DEATH_KNIGHT: - case JOB_DARK_COLLECTOR: + case JOB_GANGSI: // 622 + case JOB_DEATH_KNIGHT: // 623 + case JOB_DARK_COLLECTOR: // 624 return msg_txt(622 - JOB_GANGSI+class_); - case JOB_RUNE_KNIGHT: - case JOB_WARLOCK: - case JOB_RANGER: - case JOB_ARCH_BISHOP: - case JOB_MECHANIC: - case JOB_GUILLOTINE_CROSS: + case JOB_RUNE_KNIGHT: // 625 + case JOB_WARLOCK: // 626 + case JOB_RANGER: // 627 + case JOB_ARCH_BISHOP: // 628 + case JOB_MECHANIC: // 629 + case JOB_GUILLOTINE_CROSS: // 630 return msg_txt(625 - JOB_RUNE_KNIGHT+class_); - case JOB_RUNE_KNIGHT_T: - case JOB_WARLOCK_T: - case JOB_RANGER_T: - case JOB_ARCH_BISHOP_T: - case JOB_MECHANIC_T: - case JOB_GUILLOTINE_CROSS_T: - return msg_txt(681 - JOB_RUNE_KNIGHT_T+class_); - - case JOB_ROYAL_GUARD: - case JOB_SORCERER: - case JOB_MINSTREL: - case JOB_WANDERER: - case JOB_SURA: - case JOB_GENETIC: - case JOB_SHADOW_CHASER: + case JOB_RUNE_KNIGHT_T: // 656 + case JOB_WARLOCK_T: // 657 + case JOB_RANGER_T: // 658 + 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_); + + case JOB_ROYAL_GUARD: // 631 + case JOB_SORCERER: // 632 + case JOB_MINSTREL: // 633 + case JOB_WANDERER: // 634 + case JOB_SURA: // 635 + case JOB_GENETIC: // 636 + case JOB_SHADOW_CHASER: // 637 return msg_txt(631 - JOB_ROYAL_GUARD+class_); - case JOB_ROYAL_GUARD_T: - case JOB_SORCERER_T: - case JOB_MINSTREL_T: - case JOB_WANDERER_T: - case JOB_SURA_T: - case JOB_GENETIC_T: - case JOB_SHADOW_CHASER_T: - return msg_txt(687 - JOB_ROYAL_GUARD_T+class_); + case JOB_ROYAL_GUARD_T: // 662 + case JOB_SORCERER_T: // 663 + case JOB_MINSTREL_T: // 664 + case JOB_WANDERER_T: // 665 + 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_); case JOB_RUNE_KNIGHT2: - case JOB_RUNE_KNIGHT_T2: return msg_txt(625); + case JOB_RUNE_KNIGHT_T2: + return msg_txt(656); + case JOB_ROYAL_GUARD2: - case JOB_ROYAL_GUARD_T2: return msg_txt(631); + case JOB_ROYAL_GUARD_T2: + return msg_txt(662); + case JOB_RANGER2: - case JOB_RANGER_T2: return msg_txt(627); + case JOB_RANGER_T2: + return msg_txt(658); + case JOB_MECHANIC2: - case JOB_MECHANIC_T2: return msg_txt(629); - case JOB_BABY_RUNE: - case JOB_BABY_WARLOCK: - case JOB_BABY_RANGER: - case JOB_BABY_BISHOP: - case JOB_BABY_MECHANIC: - case JOB_BABY_CROSS: - case JOB_BABY_GUARD: - case JOB_BABY_SORCERER: - case JOB_BABY_MINSTREL: - case JOB_BABY_WANDERER: - case JOB_BABY_SURA: - case JOB_BABY_GENETIC: - case JOB_BABY_CHASER: + case JOB_MECHANIC_T2: + return msg_txt(660); + + case JOB_BABY_RUNE: // 638 + case JOB_BABY_WARLOCK: // 639 + case JOB_BABY_RANGER: // 640 + case JOB_BABY_BISHOP: // 641 + case JOB_BABY_MECHANIC: // 642 + case JOB_BABY_CROSS: // 643 + case JOB_BABY_GUARD: // 644 + case JOB_BABY_SORCERER: // 645 + case JOB_BABY_MINSTREL: // 646 + case JOB_BABY_WANDERER: // 647 + case JOB_BABY_SURA: // 648 + case JOB_BABY_GENETIC: // 649 + case JOB_BABY_CHASER: // 650 return msg_txt(638 - JOB_BABY_RUNE+class_); case JOB_BABY_RUNE2: @@ -5581,56 +5807,57 @@ const char* job_name(int class_) case JOB_BABY_MECHANIC2: return msg_txt(642); - case JOB_SUPER_NOVICE_E: - case JOB_SUPER_BABY_E: + case JOB_SUPER_NOVICE_E: // 651 + case JOB_SUPER_BABY_E: // 652 return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); - case JOB_KAGEROU: - case JOB_OBORO: + case JOB_KAGEROU: // 653 + case JOB_OBORO: // 654 return msg_txt(653 - JOB_KAGEROU+class_); - default: + case JOB_REBELLION: return msg_txt(655); + + default: + return msg_txt(620); // "Unknown Job" } } -int pc_follow_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_follow_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct block_list *tbl; - sd = iMap->id2sd(id); + sd = map->id2sd(id); nullpo_ret(sd); - if (sd->followtimer != tid){ + if (sd->followtimer != tid) { ShowError("pc_follow_timer %d != %d\n",sd->followtimer,tid); sd->followtimer = INVALID_TIMER; return 0; } sd->followtimer = INVALID_TIMER; - tbl = iMap->id2bl(sd->followtarget); + tbl = map->id2bl(sd->followtarget); - if (tbl == NULL || pc_isdead(sd) || status_isdead(tbl)) - { + if (tbl == NULL || pc_isdead(sd) || status->isdead(tbl)) { pc->stop_following(sd); return 0; } // either player or target is currently detached from map blocks (could be teleporting), // but still connected to this map, so we'll just increment the timer and check back later - if (sd->bl.prev != NULL && tbl->prev != NULL && - sd->ud.skilltimer == INVALID_TIMER && sd->ud.attacktimer == INVALID_TIMER && sd->ud.walktimer == INVALID_TIMER) - { - if((sd->bl.m == tbl->m) && unit_can_reach_bl(&sd->bl,tbl, AREA_SIZE, 0, NULL, NULL)) { + if (sd->bl.prev != NULL && tbl->prev != NULL + && sd->ud.skilltimer == INVALID_TIMER && sd->ud.attacktimer == INVALID_TIMER && sd->ud.walktimer == INVALID_TIMER + ) { + if((sd->bl.m == tbl->m) && unit->can_reach_bl(&sd->bl,tbl, AREA_SIZE, 0, NULL, NULL)) { if (!check_distance_bl(&sd->bl, tbl, 5)) - unit_walktobl(&sd->bl, tbl, 5, 0); + unit->walktobl(&sd->bl, tbl, 5, 0); } else pc->setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT); } - sd->followtimer = iTimer->add_timer( + sd->followtimer = timer->add( tick + 1000, // increase time a bit to loosen up map's load - pc_follow_timer, sd->bl.id, 0); + pc->follow_timer, sd->bl.id, 0); return 0; } @@ -5639,27 +5866,26 @@ int pc_stop_following (struct map_session_data *sd) nullpo_ret(sd); if (sd->followtimer != INVALID_TIMER) { - iTimer->delete_timer(sd->followtimer,pc_follow_timer); + timer->delete(sd->followtimer,pc->follow_timer); sd->followtimer = INVALID_TIMER; } sd->followtarget = -1; sd->ud.target_to = 0; - unit_stop_walking(&sd->bl, 1); + unit->stop_walking(&sd->bl, 1); return 0; } -int pc_follow(struct map_session_data *sd,int target_id) -{ - struct block_list *bl = iMap->id2bl(target_id); +int pc_follow(struct map_session_data *sd,int target_id) { + struct block_list *bl = map->id2bl(target_id); if (bl == NULL /*|| bl->type != BL_PC*/) return 1; if (sd->followtimer != INVALID_TIMER) pc->stop_following(sd); sd->followtarget = target_id; - pc_follow_timer(INVALID_TIMER, iTimer->gettick(), sd->bl.id, 0); + pc->follow_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0); return 0; } @@ -5683,29 +5909,29 @@ int pc_checkbaselevelup(struct map_session_data *sd) { } while ((next=pc->nextbaseexp(sd)) > 0 && sd->status.base_exp >= next); if (battle_config.pet_lv_rate && sd->pd) //<Skotlex> update pet's level - status_calc_pet(sd->pd,0); + status_calc_pet(sd->pd,SCO_NONE); clif->updatestatus(sd,SP_STATUSPOINT); clif->updatestatus(sd,SP_BASELEVEL); clif->updatestatus(sd,SP_BASEEXP); clif->updatestatus(sd,SP_NEXTBASEEXP); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); status_percent_heal(&sd->bl,100,100); if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) { - sc_start(&sd->bl,status_skill2sc(PR_KYRIE),100,1,skill->get_time(PR_KYRIE,1)); - sc_start(&sd->bl,status_skill2sc(PR_IMPOSITIO),100,1,skill->get_time(PR_IMPOSITIO,1)); - sc_start(&sd->bl,status_skill2sc(PR_MAGNIFICAT),100,1,skill->get_time(PR_MAGNIFICAT,1)); - sc_start(&sd->bl,status_skill2sc(PR_GLORIA),100,1,skill->get_time(PR_GLORIA,1)); - sc_start(&sd->bl,status_skill2sc(PR_SUFFRAGIUM),100,1,skill->get_time(PR_SUFFRAGIUM,1)); + 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)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_GLORIA),100,1,skill->get_time(PR_GLORIA,1)); + 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 ) { - sc_start(&sd->bl,status_skill2sc(AL_INCAGI),100,10,600000); - sc_start(&sd->bl,status_skill2sc(AL_BLESSING),100,10,600000); + sc_start(NULL,&sd->bl,status->skill2sc(AL_INCAGI),100,10,600000); + sc_start(NULL,&sd->bl,status->skill2sc(AL_BLESSING),100,10,600000); } clif->misceffect(&sd->bl,0); - npc_script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT + npc->script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT if(sd->status.party_id) party->send_levelup(sd); @@ -5715,7 +5941,6 @@ int pc_checkbaselevelup(struct map_session_data *sd) { } void pc_baselevelchanged(struct map_session_data *sd) { -#ifdef RENEWAL int i; for( i = 0; i < EQI_MAX; i++ ) { if( sd->equip_index[i] >= 0 ) { @@ -5723,9 +5948,8 @@ void pc_baselevelchanged(struct map_session_data *sd) { pc->unequipitem(sd, sd->equip_index[i], 3); } } -#endif - } + int pc_checkjoblevelup(struct map_session_data *sd) { unsigned int next = pc->nextjobexp(sd); @@ -5749,29 +5973,28 @@ int pc_checkjoblevelup(struct map_session_data *sd) clif->updatestatus(sd,SP_JOBEXP); clif->updatestatus(sd,SP_NEXTJOBEXP); clif->updatestatus(sd,SP_SKILLPOINT); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); clif->misceffect(&sd->bl,1); if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. - npc_script_event(sd, NPCE_JOBLVUP); + npc->script_event(sd, NPCE_JOBLVUP); return 1; } -/*========================================== - * Alters experienced based on self bonuses that do not get even shared to the party. - *------------------------------------------*/ -static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src) -{ +/** + * 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 *status = status_get_status_data(src); + struct status_data *st = status->get_status_data(src); - if (sd->expaddrace[status->race]) - bonus += sd->expaddrace[status->race]; - bonus += sd->expaddrace[status->mode&MD_BOSS?RC_BOSS:RC_NONBOSS]; + if (sd->expaddrace[st->race]) + bonus += sd->expaddrace[st->race]; + bonus += sd->expaddrace[st->mode&MD_BOSS?RC_BOSS:RC_NONBOSS]; - if (battle_config.pk_mode && - (int)(status_get_lv(src) - sd->status.base_level) >= 20) + 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] if (sd->sc.data[SC_CASH_PLUSEXP]) @@ -5784,27 +6007,36 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi *job_exp = (unsigned int) cap_value(*job_exp + (double)*job_exp * bonus/100., 1, UINT_MAX); + if( sd->status.mod_exp != 100 ) { + *base_exp = (unsigned int) cap_value((double)*base_exp * sd->status.mod_exp/100., 1, UINT_MAX); + *job_exp = (unsigned int) cap_value((double)*job_exp * sd->status.mod_exp/100., 1, UINT_MAX); + + } + 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 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[sd->bl.m].flag.pvp) // [MouseJstr] - return 0; // no exp on pvp maps + if(!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] + return false; // no exp on pvp maps 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); nextb = pc->nextbaseexp(sd); nextj = pc->nextjobexp(sd); @@ -5831,7 +6063,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) @@ -5852,18 +6085,21 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int clif->updatestatus(sd,SP_JOBEXP); } +#if PACKETVER >= 20091027 if(base_exp) - clif->displayexp(sd, base_exp, SP_BASEEXP, quest); + clif->displayexp(sd, base_exp, SP_BASEEXP, is_quest); if(job_exp) - clif->displayexp(sd, job_exp, SP_JOBEXP, quest); + clif->displayexp(sd, job_exp, SP_JOBEXP, is_quest); +#endif + if(sd->state.showexp) { 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,strlen(output)); } - return 1; + return true; } /*========================================== @@ -5871,12 +6107,12 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int *------------------------------------------*/ unsigned int pc_maxbaselv(struct map_session_data *sd) { - return 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) { - return max_level[pc->class2idx(sd->status.class_)][1]; + return pc->max_level[pc->class2idx(sd->status.class_)][1]; } /*========================================== @@ -5891,7 +6127,7 @@ unsigned int pc_nextbaseexp(struct map_session_data *sd) if(sd->status.base_level>=pc->maxbaselv(sd) || sd->status.base_level<=0) return 0; - return 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. @@ -5900,7 +6136,7 @@ unsigned int pc_thisbaseexp(struct map_session_data *sd) if(sd->status.base_level>pc->maxbaselv(sd) || sd->status.base_level<=1) return 0; - return 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]; } @@ -5918,7 +6154,7 @@ unsigned int pc_nextjobexp(struct map_session_data *sd) if(sd->status.job_level>=pc->maxjoblv(sd) || sd->status.job_level<=0) return 0; - return 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. @@ -5926,41 +6162,41 @@ unsigned int pc_thisjobexp(struct map_session_data *sd) { if(sd->status.job_level>pc->maxjoblv(sd) || sd->status.job_level<=1) return 0; - return 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. -static int pc_getstat(struct map_session_data* sd, int type) +int pc_getstat(struct map_session_data* sd, int type) { nullpo_retr(-1, sd); switch( type ) { - case SP_STR: return sd->status.str; - case SP_AGI: return sd->status.agi; - case SP_VIT: return sd->status.vit; - case SP_INT: return sd->status.int_; - case SP_DEX: return sd->status.dex; - case SP_LUK: return sd->status.luk; - default: - return -1; + case SP_STR: return sd->status.str; + case SP_AGI: return sd->status.agi; + case SP_VIT: return sd->status.vit; + case SP_INT: return sd->status.int_; + case SP_DEX: return sd->status.dex; + case SP_LUK: return sd->status.luk; + default: + return -1; } } /// Sets the specified stat to the specified value. /// Returns the new value. -static int pc_setstat(struct map_session_data* sd, int type, int val) +int pc_setstat(struct map_session_data* sd, int type, int val) { nullpo_retr(-1, sd); switch( type ) { - case SP_STR: sd->status.str = val; break; - case SP_AGI: sd->status.agi = val; break; - case SP_VIT: sd->status.vit = val; break; - case SP_INT: sd->status.int_ = val; break; - case SP_DEX: sd->status.dex = val; break; - case SP_LUK: sd->status.luk = val; break; - default: - return -1; + case SP_STR: sd->status.str = val; break; + case SP_AGI: sd->status.agi = val; break; + case SP_VIT: sd->status.vit = val; break; + case SP_INT: sd->status.int_ = val; break; + case SP_DEX: sd->status.dex = val; break; + case SP_LUK: sd->status.luk = val; break; + default: + return -1; } return val; @@ -5970,7 +6206,7 @@ static int pc_setstat(struct map_session_data* sd, int type, int val) int pc_gets_status_point(int level) { if (battle_config.use_statpoint_table) //Use values from "db/statpoint.txt" - return (statp[level+1] - statp[level]); + return (pc->statp[level+1] - pc->statp[level]); else //Default increase return ((level+15) / 5); } @@ -5985,7 +6221,7 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val) if ( val == 0 ) return 0; - low = pc_getstat(sd,type); + low = pc->getstat(sd,type); if ( low >= pc_maxparameter(sd) && val > 0 ) return 0; // Official servers show '0' when max is reached @@ -6005,60 +6241,103 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val) return sp; } -/// Raises a stat by 1. -/// Obeys max_parameter limits. -/// Subtracts stat points. -/// -/// @param type The stat to change (see enum _sp) -int pc_statusup(struct map_session_data* sd, int type) -{ - int max, need, val; +/** + * Returns the value the specified stat can be increased by with the current + * amount of available status points for the current character's class. + * + * @param sd The target character. + * @param type Stat to verify. + * @return Maximum value the stat could grow by. + */ +int pc_maxparameterincrease(struct map_session_data* sd, int type) { + int base, final, status_points = sd->status.status_point; + + base = final = pc->getstat(sd, type); + + while (final <= pc_maxparameter(sd) && status_points >= 0) { +#ifdef RENEWAL // renewal status point cost formula + status_points -= (final < 100) ? (2 + (final - 1) / 10) : (16 + 4 * ((final - 100) / 5)); +#else + status_points -= ( 1 + (final + 9) / 10 ); +#endif + final++; + } + final--; + + return final > base ? final-base : 0; +} + +/** + * Raises a stat by the specified amount. + * + * Obeys max_parameter limits. + * 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 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. + */ +bool pc_statusup(struct map_session_data* sd, int type, int increase) { + int max_increase = 0, current = 0, needed_points = 0, final_value = 0; nullpo_ret(sd); // check conditions - need = pc->need_status_point(sd,type,1); - if( type < SP_STR || type > SP_LUK || need < 0 || need > sd->status.status_point ) - { - clif->statusupack(sd,type,0,0); - return 1; + if (type < SP_STR || type > SP_LUK || increase <= 0) { + clif->statusupack(sd, type, 0, 0); + return false; } // check limits - max = pc_maxparameter(sd); - if( pc_getstat(sd,type) >= max ) - { - clif->statusupack(sd,type,0,0); - return 1; + current = pc->getstat(sd, type); + max_increase = pc->maxparameterincrease(sd, type); + increase = cap_value(increase, 0, max_increase); // cap to the maximum status points available + if (increase <= 0 || current + increase > pc_maxparameter(sd)) { + clif->statusupack(sd, type, 0, 0); + return false; + } + + // check status points + needed_points = pc->need_status_point(sd, type, increase); + if (needed_points < 0 || needed_points > sd->status.status_point) { // Sanity check + clif->statusupack(sd, type, 0, 0); + return false; } // set new values - val = pc_setstat(sd, type, pc_getstat(sd,type) + 1); - sd->status.status_point -= need; + final_value = pc->setstat(sd, type, current + increase); + sd->status.status_point -= needed_points; - status_calc_pc(sd,0); + status_calc_pc(sd, SCO_NONE); // update increase cost indicator - if( need != pc->need_status_point(sd,type,1) ) - clif->updatestatus(sd, SP_USTR + type-SP_STR); + clif->updatestatus(sd, SP_USTR + type-SP_STR); // update statpoint count - clif->updatestatus(sd,SP_STATUSPOINT); + clif->updatestatus(sd, SP_STATUSPOINT); // update stat value - clif->statusupack(sd,type,1,val); // required - if( val > 255 ) - clif->updatestatus(sd,type); // send after the 'ack' to override the truncated value + clif->statusupack(sd, type, 1, final_value); // required + if (final_value > 255) + clif->updatestatus(sd, type); // send after the 'ack' to override the truncated value - return 0; + return true; } -/// Raises a stat by the specified amount. -/// Obeys max_parameter limits. -/// Does not subtract stat points. -/// -/// @param type The stat to change (see enum _sp) -/// @param val The stat increase amount. +/** + * Raises a stat by the specified amount. + * + * Obeys max_parameter limits. + * 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 status_point_types) + * @param val The stat increase (or decrease) amount. + * @return the stat increase amount. + * @retval 0 if no changes were made. + */ int pc_statusup2(struct map_session_data* sd, int type, int val) { int max, need; @@ -6067,16 +6346,16 @@ int pc_statusup2(struct map_session_data* sd, int type, int val) if( type < SP_STR || type > SP_LUK ) { clif->statusupack(sd,type,0,0); - return 1; + return 0; } need = pc->need_status_point(sd,type,1); // set new value max = pc_maxparameter(sd); - val = pc_setstat(sd, type, cap_value(pc_getstat(sd,type) + val, 1, max)); + val = pc->setstat(sd, type, cap_value(pc->getstat(sd,type) + val, 1, max)); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); // update increase cost indicator if( need != pc->need_status_point(sd,type,1) ) @@ -6087,7 +6366,7 @@ int pc_statusup2(struct map_session_data* sd, int type, int val) if( val > 255 ) clif->updatestatus(sd,type); // send after the 'ack' to override the truncated value - return 0; + return val; } /*========================================== @@ -6110,7 +6389,7 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { if( !(index = skill->get_index(skill_id)) ) return 0; - + 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] @@ -6118,34 +6397,29 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { { sd->status.skill[index].lv++; sd->status.skill_point--; - if( !skill_db[index].inf ) - status_calc_pc(sd,0); // Only recalculate for passive skills. + if( !skill->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) ) 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 + pc->check_skilltree(sd, skill_id); // Check if a new skill can Lvlup - clif->skillup(sd,skill_id); + clif->skillup(sd,skill_id, sd->status.skill[index].lv, 1); clif->updatestatus(sd,SP_SKILLPOINT); if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ clif->updatestatus(sd,SP_CARTINFO); 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 ){ - int pts = 0, i, id; - for(i = 0; i < MAX_SKILL_TREE && (id=skill_tree[pc_class2idx(sd->status.class_)][i].id) > 0 ; i++){ - int inf2 = skill->get_inf2(id); - if ( inf2&INF2_QUEST_SKILL || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || id == NV_BASIC ) - continue; - if( sd->status.skill[id].id && sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) - pts += pc_checkskill(sd, id); + } else if( battle_config.skillup_limit ){ + if( sd->sktree.second ) + clif->msg_value(sd, 0x61E, sd->sktree.second); + else if( sd->sktree.third ) + clif->msg_value(sd, 0x61F, sd->sktree.third); + else if( pc->calc_skillpoint(sd) < 9 ) { + /* TODO: official response? */ + clif->colormes(sd->fd,COLOR_RED,"You need the basic skills"); } - if( pts < sd->change_level_2nd ) - clif->msg_value(sd, 0x61E, sd->change_level_2nd-pts); - else if( pts < (sd->change_level_3rd + sd->change_level_2nd) ) - clif->msg_value(sd, 0x61F, sd->change_level_3rd - (pts - sd->change_level_2nd)); } - return 0; } @@ -6170,22 +6444,22 @@ int pc_allskillup(struct map_session_data *sd) if (pc_has_permission(sd, PC_PERM_ALL_SKILL)) { //Get ALL skills except npc/guild ones. [Skotlex] //and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage] for(i=0;i<MAX_SKILL;i++){ - switch( skill_db[i].nameid ) { + switch( skill->db[i].nameid ) { case SG_DEVIL: case MO_TRIPLEATTACK: case RG_SNATCHER: continue; default: - if( !(skill_db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) ) - if ( ( sd->status.skill[i].lv = skill_db[i].max ) )//Nonexistant skills should return a max of 0 anyway. - sd->status.skill[i].id = skill_db[i].nameid; + if( !(skill->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) ) + if ( ( sd->status.skill[i].lv = skill->db[i].max ) )//Nonexistant skills should return a max of 0 anyway. + sd->status.skill[i].id = skill->db[i].nameid; } } } else { int inf2; - for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[pc->class2idx(sd->status.class_)][i].id)>0;i++){ - int idx = skill_tree[pc->class2idx(sd->status.class_)][i].idx; - inf2 = skill_db[idx].inf2; + 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; + inf2 = skill->db[idx].inf2; if ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || @@ -6197,7 +6471,7 @@ int pc_allskillup(struct map_session_data *sd) sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_); // celest } } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); //Required because if you could level up all skills previously, //the update will not be sent as only the lv variable changes. clif->skillinfoblock(sd); @@ -6287,7 +6561,7 @@ int pc_resetlvl(struct map_session_data* sd,int type) if ((type == 1 || type == 2 || type == 3) && sd->status.party_id) party->send_levelup(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); clif->skillinfoblock(sd); return 0; @@ -6302,33 +6576,33 @@ int pc_resetstate(struct map_session_data* sd) if (battle_config.use_statpoint_table) { // New statpoint table used here - Dexity if (sd->status.base_level > MAX_LEVEL) - { //statp[] goes out of bounds, can't reset! + { //pc->statp[] goes out of bounds, can't reset! ShowError("pc_resetstate: Can't reset stats of %d:%d, the base level (%d) is greater than the max level supported (%d)\n", sd->status.account_id, sd->status.char_id, sd->status.base_level, MAX_LEVEL); return 0; } - sd->status.status_point = 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->class_&JOBL_UPPER ? 52 : 0 ); // extra 52+48=100 stat points } else { int add=0; - add += pc->need_status_point(sd, SP_STR, 1-pc_getstat(sd, SP_STR)); - add += pc->need_status_point(sd, SP_AGI, 1-pc_getstat(sd, SP_AGI)); - add += pc->need_status_point(sd, SP_VIT, 1-pc_getstat(sd, SP_VIT)); - add += pc->need_status_point(sd, SP_INT, 1-pc_getstat(sd, SP_INT)); - add += pc->need_status_point(sd, SP_DEX, 1-pc_getstat(sd, SP_DEX)); - add += pc->need_status_point(sd, SP_LUK, 1-pc_getstat(sd, SP_LUK)); + add += pc->need_status_point(sd, SP_STR, 1-pc->getstat(sd, SP_STR)); + add += pc->need_status_point(sd, SP_AGI, 1-pc->getstat(sd, SP_AGI)); + add += pc->need_status_point(sd, SP_VIT, 1-pc->getstat(sd, SP_VIT)); + add += pc->need_status_point(sd, SP_INT, 1-pc->getstat(sd, SP_INT)); + add += pc->need_status_point(sd, SP_DEX, 1-pc->getstat(sd, SP_DEX)); + add += pc->need_status_point(sd, SP_LUK, 1-pc->getstat(sd, SP_LUK)); sd->status.status_point+=add; } - pc_setstat(sd, SP_STR, 1); - pc_setstat(sd, SP_AGI, 1); - pc_setstat(sd, SP_VIT, 1); - pc_setstat(sd, SP_INT, 1); - pc_setstat(sd, SP_DEX, 1); - pc_setstat(sd, SP_LUK, 1); + pc->setstat(sd, SP_STR, 1); + pc->setstat(sd, SP_AGI, 1); + pc->setstat(sd, SP_VIT, 1); + pc->setstat(sd, SP_INT, 1); + pc->setstat(sd, SP_DEX, 1); + pc->setstat(sd, SP_LUK, 1); clif->updatestatus(sd,SP_STR); clif->updatestatus(sd,SP_AGI); @@ -6349,10 +6623,10 @@ int pc_resetstate(struct map_session_data* sd) if( sd->mission_mobid ) { //bugreport:2200 sd->mission_mobid = 0; sd->mission_count = 0; - pc_setglobalreg(sd,"TK_MISSION_ID", 0); + pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), 0); } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 1; } @@ -6382,7 +6656,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; @@ -6405,7 +6679,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) pc->setoption(sd, i); if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) ) - homun->vaporize(sd, 0); + homun->vaporize(sd, HOM_ST_REST); } for( i = 1; i < MAX_SKILL; i++ ) { @@ -6413,22 +6687,22 @@ int pc_resetskill(struct map_session_data* sd, int flag) lv = sd->status.skill[i].lv; if (lv < 1) continue; - inf2 = skill_db[i].inf2; + inf2 = skill->db[i].inf2; if( inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL) ) //Avoid reseting wedding/linker skills. continue; - skill_id = skill_db[i].nameid; + skill_id = skill->db[i].nameid; // Don't reset trick dead if not a novice/baby - if( skill_id == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != 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_UPPERMASK) != 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 ) @@ -6447,8 +6721,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) } if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) skill_point += lv; - else - if( sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0 ) + else if( sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 ) skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); if( !(flag&2) ) {// reset @@ -6461,10 +6734,25 @@ 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); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); } return skill_point; @@ -6482,7 +6770,7 @@ int pc_resetfeel(struct map_session_data* sd) { sd->feel_map[i].m = -1; sd->feel_map[i].index = 0; - pc_setglobalreg(sd,sg_info[i].feel_var,0); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),0); } return 0; @@ -6496,7 +6784,7 @@ int pc_resethate(struct map_session_data* sd) for (i=0; i<3; i++) { sd->hate_mob[i] = -1; - pc_setglobalreg(sd,sg_info[i].hate_var,0); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].hate_var),0); } return 0; } @@ -6551,7 +6839,7 @@ void pc_respawn(struct map_session_data* sd, clr_type clrtype) { if( !pc_isdead(sd) ) return; // not applicable - if( sd->bg_id && bg_member_respawn(sd) ) + if( sd->bg_id && bg->member_respawn(sd) ) return; // member revived by battleground pc->setstand(sd); @@ -6560,9 +6848,8 @@ void pc_respawn(struct map_session_data* sd, clr_type clrtype) clif->resurrection(&sd->bl, 1); //If warping fails, send a normal stand up packet. } -static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_respawn_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); if( sd != NULL ) { sd->pvp_point=0; @@ -6589,86 +6876,89 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h skill->sit(sd,0); } - if( sd->progressbar.npc_id ) + if( sd->progressbar.npc_id ){ clif->progressbar_abort(sd); + sd->state.workinprogress = 0; + } if( sd->status.pet_id > 0 && sd->pd && battle_config.pet_damage_support ) - pet_target_check(sd,src,1); + pet->target_check(sd,src,1); if( sd->status.ele_id > 0 ) - elemental_set_target(sd,src); + elemental->set_target(sd,src); - sd->canlog_tick = iTimer->gettick(); + sd->canlog_tick = timer->gettick(); } /*========================================== * Invoked when a player has negative current hp *------------------------------------------*/ int pc_dead(struct map_session_data *sd,struct block_list *src) { - int i=0,j=0,k=0; - unsigned int tick = iTimer->gettick(); + int i=0,j=0; + int64 tick = timer->gettick(); - for(k = 0; k < 5; k++) - if (sd->devotion[k]){ - struct map_session_data *devsd = iMap->id2sd(sd->devotion[k]); + 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[k] = 0; + sd->devotion[j] = 0; } + } if(sd->status.pet_id > 0 && sd->pd) { struct pet_data *pd = sd->pd; - if( !map[sd->bl.m].flag.noexppenalty ) { - pet_set_intimate(pd, pd->pet.intimate - pd->petDB->die); + if( !map->list[sd->bl.m].flag.noexppenalty ) { + pet->set_intimate(pd, pd->pet.intimate - pd->petDB->die); if( pd->pet.intimate < 0 ) pd->pet.intimate = 0; clif->send_petdata(sd,sd->pd,1,pd->pet.intimate); } if( sd->pd->target_id ) // Unlock all targets... - pet_unlocktarget(sd->pd); + pet->unlocktarget(sd->pd); } if (sd->status.hom_id > 0){ - if(battle_config.homunculus_auto_vapor && sd->hd && !sd->hd->sc.data[SC_LIGHT_OF_REGENE]) - homun->vaporize(sd, 0); + if(battle_config.homunculus_auto_vapor && sd->hd) + homun->vaporize(sd, HOM_ST_REST); } if( sd->md ) - merc_delete(sd->md, 3); // Your mercenary soldier has ran away. + mercenary->delete(sd->md, 3); // Your mercenary soldier has ran away. if( sd->ed ) - elemental_delete(sd->ed, 0); + elemental->delete(sd->ed, 0); // Leave duel if you die [LuzZza] if(battle_config.duel_autoleave_when_die) { if(sd->duel_group > 0) - duel_leave(sd->duel_group, sd); + duel->leave(sd->duel_group, sd); if(sd->duel_invite > 0) - duel_reject(sd->duel_invite, sd); + duel->reject(sd->duel_invite, sd); } if (sd->npc_id && sd->st && sd->st->state != RUN) - npc_event_dequeue(sd); + npc->event_dequeue(sd); - pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1); + pc_setglobalreg(sd,script->add_str("PC_DIE_COUNTER"),sd->die_counter+1); pc->setparam(sd, SP_KILLERRID, src?src->id:0); if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */ - struct battleground_data *bg; - if( (bg = bg_team_search(sd->bg_id)) != NULL && bg->die_event[0] ) - npc_event(sd, bg->die_event, 0); + struct battleground_data *bgd; + if( (bgd = bg->team_search(sd->bg_id)) != NULL && bgd->die_event[0] ) + npc->event(sd, bgd->die_event, 0); } for( i = 0; i < sd->queues_count; i++ ) { struct hQueue *queue; if( (queue = script->queue(sd->queues[i])) && queue->onDeath[0] != '\0' ) - npc_event(sd, queue->onDeath, 0); + npc->event(sd, queue->onDeath, 0); } - npc_script_event(sd,NPCE_DIE); + npc->script_event(sd,NPCE_DIE); // Clear anything NPC-related when you die and was interacting with one. - if (sd->npc_id || sd->npc_shopid) { + if ( (sd->npc_id || sd->npc_shopid) && sd->state.dialog) { if (sd->state.using_fake_npc) { clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; @@ -6710,14 +7000,14 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { { struct mob_data *md=(struct mob_data *)src; if(md->target_id==sd->bl.id) - mob_unlocktarget(md,tick); + mob->unlocktarget(md,tick); if(battle_config.mobs_level_up && md->status.hp && (unsigned int)md->level < pc->maxbaselv(sd) && !md->guardian_data && !md->special_state.ai// Guardians/summons should not level. [Skotlex] ) { // monster level up [Valaris] clif->misceffect(&md->bl,0); md->level++; - status_calc_mob(md, 0); + status_calc_mob(md, SCO_NONE); status_percent_heal(src,10,0); if( battle_config.show_mob_info&4 ) @@ -6743,12 +7033,12 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { if (src && src->type == BL_PC) { struct map_session_data *ssd = (struct map_session_data *)src; pc->setparam(ssd, SP_KILLEDRID, sd->bl.id); - npc_script_event(ssd, NPCE_KILLPC); + npc->script_event(ssd, NPCE_KILLPC); if (battle_config.pk_mode&2) { ssd->status.manner -= 5; if(ssd->status.manner < 0) - sc_start(src,SC_NOCHAT,100,0,0); + sc_start(NULL,src,SC_NOCHAT,100,0,0); #if 0 // PK/Karma system code (not enabled yet) [celest] // originally from Kade Online, so i don't know if any of these is correct ^^; @@ -6775,9 +7065,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } } - if(battle_config.bone_drop==2 - || (battle_config.bone_drop==1 && map[sd->bl.m].flag.pvp)) - { + if( battle_config.bone_drop==2 + || (battle_config.bone_drop==1 && map->list[sd->bl.m].flag.pvp) + ) { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=ITEMID_SKULL_; @@ -6786,12 +7076,11 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { item_tmp.card[1]=0; item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId item_tmp.card[3]=GetWord(sd->status.char_id,1); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } // 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->class_&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 ) { @@ -6801,79 +7090,86 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { clif->resurrection(&sd->bl, 1); if(battle_config.pc_invincible_time) pc->setinvincibletimer(sd, battle_config.pc_invincible_time); - sc_start(&sd->bl,status_skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1)); - if(map_flag_gvg(sd->bl.m)) - pc_respawn_timer(INVALID_TIMER, iTimer->gettick(), sd->bl.id, 0); + sc_start(NULL,&sd->bl,status->skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1)); + if(map_flag_gvg2(sd->bl.m)) + pc->respawn_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0); return 0; } } // 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 - && !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m) - && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]) - { - unsigned int base_penalty =0; + if( battle_config.death_penalty_type + && (sd->class_&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] + ) { + unsigned int base_penalty = 0; if (battle_config.death_penalty_base > 0) { + switch (battle_config.death_penalty_type) { case 1: base_penalty = (unsigned int) ((double)pc->nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000); - break; + break; case 2: base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000); - break; + break; } + if(base_penalty) { if (battle_config.pk_mode && src && src->type==BL_PC) base_penalty*=2; + if( sd->status.mod_death != 100 ) + base_penalty = base_penalty * sd->status.mod_death / 100; sd->status.base_exp -= min(sd->status.base_exp, base_penalty); clif->updatestatus(sd,SP_BASEEXP); } } - if(battle_config.death_penalty_job > 0) - { + + if(battle_config.death_penalty_job > 0) { base_penalty = 0; + switch (battle_config.death_penalty_type) { case 1: base_penalty = (unsigned int) ((double)pc->nextjobexp(sd) * (double)battle_config.death_penalty_job/10000); - break; + break; case 2: base_penalty = (unsigned int) ((double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000); - break; + break; } + if(base_penalty) { if (battle_config.pk_mode && src && src->type==BL_PC) base_penalty*=2; + if( sd->status.mod_death != 100 ) + base_penalty = base_penalty * sd->status.mod_death / 100; sd->status.job_exp -= min(sd->status.job_exp, base_penalty); clif->updatestatus(sd,SP_JOBEXP); } } - if(battle_config.zeny_penalty > 0 && !map[sd->bl.m].flag.nozenypenalty) - { + + if(battle_config.zeny_penalty > 0 && !map->list[sd->bl.m].flag.nozenypenalty) { base_penalty = (unsigned int)((double)sd->status.zeny * (double)battle_config.zeny_penalty / 10000.); if(base_penalty) pc->payzeny(sd, base_penalty, LOG_TYPE_PICKDROP_PLAYER, NULL); } } - if(map[sd->bl.m].flag.pvp_nightmaredrop) - { // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker] - for(j=0;j<map[sd->bl.m].drop_list_count;j++){ - int id = map[sd->bl.m].drop_list[j].drop_id; - int type = map[sd->bl.m].drop_list[j].drop_type; - int per = map[sd->bl.m].drop_list[j].drop_per; + if(map->list[sd->bl.m].flag.pvp_nightmaredrop) { + // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker] + for(j=0;j<map->list[sd->bl.m].drop_list_count;j++){ + int id = map->list[sd->bl.m].drop_list[j].drop_id; + int type = map->list[sd->bl.m].drop_list[j].drop_type; + int per = map->list[sd->bl.m].drop_list[j].drop_per; if(id == 0) continue; if(id == -1){ - int eq_num=0,eq_n[MAX_INVENTORY]; + int eq_num=0,eq_n[MAX_INVENTORY],k; memset(eq_n,0,sizeof(eq_n)); for(i=0;i<MAX_INVENTORY;i++){ if( (type == 1 && !sd->status.inventory[i].equip) || (type == 2 && sd->status.inventory[i].equip) || type == 3) { - int k; ARR_FIND( 0, MAX_INVENTORY, k, eq_n[k] <= 0 ); if( k < MAX_INVENTORY ) eq_n[k] = i; @@ -6906,10 +7202,20 @@ 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[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map[sd->bl.m].flag.pvp_nocalcrank ) - { + if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) { sd->pvp_point -= 5; sd->pvp_lost++; if( src && src->type == BL_PC ) @@ -6920,30 +7226,26 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } if( sd->pvp_point < 0 ) { - iTimer->add_timer(tick+1000, pc_respawn_timer,sd->bl.id,0); + timer->add(tick+1, pc->respawn_timer,sd->bl.id,0); return 1|8; } } //GvG - if( map_flag_gvg(sd->bl.m) ) - { - iTimer->add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); + if( map_flag_gvg2(sd->bl.m) ) { + timer->add(tick+1, pc->respawn_timer, sd->bl.id, 0); return 1|8; - } - else if( sd->bg_id ) - { - struct battleground_data *bg = bg_team_search(sd->bg_id); - if( bg && bg->mapindex > 0 ) - { // Respawn by BG - iTimer->add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); + } else if( sd->bg_id ) { + struct battleground_data *bgd = bg->team_search(sd->bg_id); + if( bgd && bgd->mapindex > 0 ) { // Respawn by BG + timer->add(tick+1000, pc->respawn_timer, sd->bl.id, 0); return 1|8; } } - //Reset "can log out" tick. if( battle_config.prevent_logout ) - sd->canlog_tick = iTimer->gettick() - battle_config.prevent_logout; + sd->canlog_tick = timer->gettick() - battle_config.prevent_logout; + return 1; } @@ -6956,10 +7258,10 @@ void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { pc->setinvincibletimer(sd, battle_config.pc_invincible_time); if( sd->state.gmaster_flag ) { - guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->state.gmaster_flag,GD_LEADERSHIP)); - guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->state.gmaster_flag,GD_GLORYWOUNDS)); - guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->state.gmaster_flag,GD_SOULCOLD)); - guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->state.gmaster_flag,GD_HAWKEYES)); + guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP)); + guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS)); + guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD)); + guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES)); } } // script @@ -7007,6 +7309,9 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_KILLEDRID: val = sd->killedrid; break; case SP_SLOTCHANGE: val = sd->status.slotchange; break; case SP_CHARRENAME: val = sd->status.rename; break; + case SP_MOD_EXP: val = sd->status.mod_exp; break; + case SP_MOD_DROP: val = sd->status.mod_drop; break; + case SP_MOD_DEATH: val = sd->status.mod_death; break; case SP_CRITICAL: val = sd->battle_status.cri/10; break; case SP_ASPD: val = (2000-sd->battle_status.amotion)/10; break; case SP_BASE_ATK: val = sd->battle_status.batk; break; @@ -7020,7 +7325,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; @@ -7139,7 +7444,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) clif->updatestatus(sd, SP_NEXTBASEEXP); clif->updatestatus(sd, SP_STATUSPOINT); clif->updatestatus(sd, SP_BASEEXP); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); if(sd->status.party_id) { party->send_levelup(sd); @@ -7156,7 +7461,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) // clif->updatestatus(sd, SP_JOBLEVEL); // Gets updated at the bottom clif->updatestatus(sd, SP_NEXTJOBEXP); clif->updatestatus(sd, SP_JOBEXP); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); break; case SP_SKILLPOINT: sd->status.skill_point = val; @@ -7238,7 +7543,13 @@ int pc_setparam(struct map_session_data *sd,int type,int val) break; case SP_MANNER: sd->status.manner = val; - break; + if( val < 0 ) + sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0); + else { + status_change_end(&sd->bl, SC_NOCHAT, INVALID_TIMER); + clif->manner_message(sd, 5); + } + return 1; // status_change_start/status_change_end already sends packets warning the client case SP_FAME: sd->status.fame = val; break; @@ -7254,6 +7565,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val) case SP_CHARRENAME: sd->status.rename = val; return 1; + case SP_MOD_EXP: + sd->status.mod_exp = val; + return 1; + case SP_MOD_DROP: + sd->status.mod_drop = val; + return 1; + case SP_MOD_DEATH: + sd->status.mod_death = val; + return 1; default: ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type); return 0; @@ -7289,7 +7609,7 @@ void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int ty *------------------------------------------*/ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) { - int bonus; + int bonus, tmp; if(hp) { int i; @@ -7297,22 +7617,22 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) + pc->checkskill(sd,SM_RECOVERY)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5; // A potion produced by an Alchemist in the Fame Top 10 gets +50% effect [DracoRPG] - if (potion_flag > 1) - bonus += bonus*(potion_flag-1)*50/100; + if (script->potion_flag > 1) + bonus += bonus*(script->potion_flag-1)*50/100; //All item bonuses. bonus += sd->bonus.itemhealrate2; - //Item Group bonuses - bonus += bonus*itemdb_group_bonus(sd, itemid)/100; //Individual item bonuses. - for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) - { - if (sd->itemhealrate[i].nameid == itemid) { + for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) { + struct item_data *it = itemdb->exists(sd->itemhealrate[i].nameid); + if (sd->itemhealrate[i].nameid == itemid || (it && it->group && itemdb->in_group(it->group,itemid))) { bonus += bonus*sd->itemhealrate[i].rate/100; break; } } - if(bonus!=100) - hp = hp * bonus / 100; + + tmp = hp*bonus/100; + if(bonus != 100 && tmp > hp) + hp = tmp; // Recovery Potion if( sd->sc.data[SC_HEALPLUS] ) @@ -7322,10 +7642,12 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) bonus = 100 + (sd->battle_status.int_<<1) + pc->checkskill(sd,MG_SRECOVERY)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5; - if (potion_flag > 1) - bonus += bonus*(potion_flag-1)*50/100; - if(bonus != 100) - sp = sp * bonus / 100; + if (script->potion_flag > 1) + bonus += bonus*(script->potion_flag-1)*50/100; + + tmp = sp*bonus/100; + if(bonus != 100 && tmp > sp) + sp = tmp; } if( sd->sc.count ) { if ( sd->sc.data[SC_CRITICALWOUND] ) { @@ -7333,6 +7655,11 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100; } + if( sd->sc.data[SC_VITALITYACTIVATION] ){ + hp += hp / 2; // 1.5 times + sp -= sp / 2; + } + if ( sd->sc.data[SC_DEATHHURT] ) { hp -= hp * 20 / 100; sp -= sp * 20 / 100; @@ -7348,7 +7675,7 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) #endif } - return status_heal(&sd->bl, hp, sp, 1); + return status->heal(&sd->bl, hp, sp, 1); } /*========================================== @@ -7390,7 +7717,7 @@ int pc_percentheal(struct map_session_data *sd,int hp,int sp) return 0; } -static int jobchange_killclone(struct block_list *bl, va_list ap) +int jobchange_killclone(struct block_list *bl, va_list ap) { struct mob_data *md; int flag; @@ -7441,12 +7768,12 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) // changing from 1st to 2nd job if ((b_class&JOBL_2) && !(sd->class_&JOBL_2) && (b_class&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) { sd->change_level_2nd = sd->status.job_level; - pc_setglobalreg (sd, "jobchange_level", sd->change_level_2nd); + 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)) { sd->change_level_3rd = sd->status.job_level; - pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd); + pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); } if(sd->cloneskill_id) { @@ -7458,8 +7785,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->deleteskill(sd,sd->cloneskill_id); } sd->cloneskill_id = 0; - pc_setglobalreg(sd, "CLONE_SKILL", 0); - pc_setglobalreg(sd, "CLONE_SKILL_LV", 0); + pc_setglobalreg(sd, script->add_str("CLONE_SKILL"), 0); + pc_setglobalreg(sd, script->add_str("CLONE_SKILL_LV"), 0); } if(sd->reproduceskill_id) { @@ -7471,16 +7798,16 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->deleteskill(sd,sd->reproduceskill_id); } sd->reproduceskill_id = 0; - pc_setglobalreg(sd, "REPRODUCE_SKILL",0); - pc_setglobalreg(sd, "REPRODUCE_SKILL_LV",0); + pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL"),0); + 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_); short id; - for(i = 0; i < MAX_SKILL_TREE && (id = skill_tree[class_][i].id) > 0; i++) { + for(i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[class_][i].id) > 0; i++) { //Remove status specific to your current tree skills. - enum sc_type sc = status_skill2sc(id); + enum sc_type sc = status->skill2sc(id); if (sc > SC_COMMON_MAX && sd->sc.data[sc]) status_change_end(&sd->bl, sc, INVALID_TIMER); } @@ -7522,7 +7849,7 @@ 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); + 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] if(sd->vd.cloth_color) clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); @@ -7532,11 +7859,11 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->skillinfoblock(sd); if (sd->ed) - elemental_delete(sd->ed, 0); + elemental->delete(sd->ed, 0); if (sd->state.vending) vending->close(sd); - iMap->foreachinmap(jobchange_killclone, sd->bl.m, BL_MOB, sd->bl.id); + map->foreachinmap(pc->jobchange_killclone, sd->bl.m, BL_MOB, sd->bl.id); //Remove peco/cart/falcon i = sd->sc.option; @@ -7563,27 +7890,27 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) pc->setoption(sd, i); if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN)) - homun->vaporize(sd, 0); + homun->vaporize(sd, HOM_ST_REST); if(sd->status.manner < 0) clif->changestatus(sd,SP_MANNER,sd->status.manner); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); pc->checkallowskill(sd); pc->equiplookall(sd); //if you were previously famous, not anymore. if (fame_flag) { - chrif_save(sd,0); - chrif_buildfamelist(); + 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) { case MAPID_BLACKSMITH: case MAPID_ALCHEMIST: case MAPID_TAEKWON: - chrif_save(sd,0); - chrif_buildfamelist(); + chrif->save(sd,0); + chrif->buildfamelist(); break; } } @@ -7617,7 +7944,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) switch(type){ case LOOK_BASE: - status_set_viewdata(&sd->bl, val); + status->set_viewdata(&sd->bl, val); clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); if (sd->vd.cloth_color) @@ -7631,7 +7958,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) if (sd->status.hair != val) { sd->status.hair=val; if (sd->status.guild_id) //Update Guild Window. [Skotlex] - intif_guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, + intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, GMI_HAIR,&sd->status.hair,sizeof(sd->status.hair)); } break; @@ -7653,7 +7980,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) if (sd->status.hair_color != val) { sd->status.hair_color=val; if (sd->status.guild_id) //Update Guild Window. [Skotlex] - intif_guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, + intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, GMI_HAIR_COLOR,&sd->status.hair_color,sizeof(sd->status.hair_color)); } break; @@ -7691,11 +8018,11 @@ int pc_setoption(struct map_session_data *sd,int type) if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc->checkskill(sd,RK_DRAGONTRAINING) > 0) ) { // Mounting clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_RIDING, 0, 0, 0); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON) ) { // Dismount clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_RIDING); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } #ifndef NEW_CARTS @@ -7703,11 +8030,11 @@ int pc_setoption(struct map_session_data *sd,int type) clif->cartlist(sd); clif->updatestatus(sd, SP_CARTINFO); if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Apply speed penalty. + status_calc_pc(sd,SCO_NONE); //Apply speed penalty. } else if( !( type&OPTION_CART ) && p_type&OPTION_CART ){ //Cart Off clif->clearcart(sd->fd); if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Remove speed penalty. + status_calc_pc(sd,SCO_NONE); //Remove speed penalty. } #endif @@ -7716,25 +8043,24 @@ 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,0); - } 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,0); - } + 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, 0); - else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) - status_calc_pc(sd, 0); - for( i = 0; i < SC_MAX; i++ ){ - if ( !sd->sc.data[i] || !status_get_sc_type(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 ) + if ( status->get_sc_type(i)&SC_MADO_NO_RESET ) continue; switch (i) { case SC_BERSERK: @@ -7755,7 +8081,7 @@ 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_); + status->set_viewdata(&sd->bl, sd->status.class_); new_look = sd->vd.class_; } @@ -7773,7 +8099,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); @@ -7801,7 +8127,7 @@ int pc_setcart(struct map_session_data *sd,int type) { if( !sd->sc.data[SC_PUSH_CART] ) /* first time, so fill cart data */ clif->cartlist(sd); clif->updatestatus(sd, SP_CARTINFO); - sc_start(&sd->bl, SC_PUSH_CART, 100, type, 0); + sc_start(NULL,&sd->bl, SC_PUSH_CART, 100, type, 0); clif->sc_load(&sd->bl, sd->bl.id, AREA, SI_ON_PUSH_CART, type, 0, 0); if( sd->sc.data[SC_PUSH_CART] )/* forcefully update */ sd->sc.data[SC_PUSH_CART]->val1 = type; @@ -7809,7 +8135,7 @@ int pc_setcart(struct map_session_data *sd,int type) { } if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Recalc speed penalty. + status_calc_pc(sd,SCO_NONE); //Recalc speed penalty. #else // Update option option = sd->sc.option; @@ -7851,375 +8177,322 @@ 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; -} - -/*========================================== - * Check if player can drop an item - *------------------------------------------*/ -int pc_candrop(struct map_session_data *sd, struct item *item) -{ - if( item && item->expire_time ) - return 0; - if( !pc->can_give_items(sd) ) //check if this GM level can drop items - return 0; - return (itemdb_isdropable(item, pc->get_group_level(sd))); + return; } -/*========================================== - * Read ram register for player sd - * get val (int) from reg for player sd - *------------------------------------------*/ -int pc_readreg(struct map_session_data* sd, int reg) -{ - int i; +/** + * 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); - nullpo_ret(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; - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg ); - return ( i < sd->reg_num ) ? sd->reg[i].data : 0; + return true; } -/*========================================== - * Set ram register for player sd - * memo val(int) at reg for player sd - *------------------------------------------*/ -int pc_setreg(struct map_session_data* sd, int reg, int val) -{ - int i; - nullpo_ret(sd); - - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg ); - if( i < sd->reg_num ) - {// overwrite existing entry - sd->reg[i].data = val; - return 1; - } +/** + * 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); - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].data == 0 ); - if( i == sd->reg_num ) - {// nothing free, increase size - sd->reg_num++; - RECREATE(sd->reg, struct script_reg, sd->reg_num); - } - sd->reg[i].index = reg; - sd->reg[i].data = val; + 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 1; + return true; } /*========================================== - * Read ram register for player sd - * get val (str) from reg for player sd + * Check if player can drop an item *------------------------------------------*/ -char* pc_readregstr(struct map_session_data* sd, int reg) +int pc_candrop(struct map_session_data *sd, struct item *item) { - int i; + if( item && (item->expire_time || (item->bound && !pc_can_give_bound_items(sd))) ) + return 0; + if( !pc_can_give_items(sd) ) //check if this GM level can drop items + return 0; + return (itemdb_isdropable(item, pc_get_group_level(sd))); +} +/** + * For '@type' variables (temporary numeric char reg) + **/ +int pc_readreg(struct map_session_data* sd, int64 reg) { + return i64db_iget(sd->regs.vars, reg); +} +/** + * For '@type' variables (temporary numeric char reg) + **/ +void pc_setreg(struct map_session_data* sd, int64 reg, int val) { + unsigned int index = script_getvaridx(reg); + + if( val ) { + i64db_iput(sd->regs.vars, reg, val); + if( index ) + script->array_update(&sd->regs, reg, false); + } else { + i64db_remove(sd->regs.vars, reg); + if( index ) + script->array_update(&sd->regs, reg, true); + } +} - nullpo_ret(sd); +/** + * For '@type$' variables (temporary string char reg) + **/ +char* pc_readregstr(struct map_session_data* sd, int64 reg) { + struct script_reg_str *p = NULL; - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg ); - return ( i < sd->regstr_num ) ? sd->regstr[i].data : NULL; + p = i64db_get(sd->regs.vars, reg); + + return p ? p->value : NULL; } -/*========================================== - * Set ram register for player sd - * memo val(str) at reg for player sd - *------------------------------------------*/ -int pc_setregstr(struct map_session_data* sd, int reg, const char* str) -{ - int i; - - nullpo_ret(sd); +/** + * For '@type$' variables (temporary string char 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; - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg ); - if( i < sd->regstr_num ) - {// found entry, update - if( str == NULL || *str == '\0' ) - {// empty string - if( sd->regstr[i].data != NULL ) - aFree(sd->regstr[i].data); - sd->regstr[i].data = NULL; - } - else if( sd->regstr[i].data ) - {// recreate - size_t len = strlen(str)+1; - RECREATE(sd->regstr[i].data, char, len); - memcpy(sd->regstr[i].data, str, len*sizeof(char)); + if( str[0] ) { + p = ers_alloc(pc->str_reg_ers, struct script_reg_str); + + p->value = aStrdup(str); + p->flag.type = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + } else { + if( index ) + script->array_update(&sd->regs, reg, false); } - else - {// create - sd->regstr[i].data = aStrdup(str); + } else { + if( sd->regs.vars->remove(sd->regs.vars, DB->i642key(reg), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + if( index ) + script->array_update(&sd->regs, reg, true); } - return 1; } - - if( str == NULL || *str == '\0' ) - return 1;// nothing to add, empty string - - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].data == NULL ); - if( i == sd->regstr_num ) - {// nothing free, increase size - sd->regstr_num++; - RECREATE(sd->regstr, struct script_regstr, sd->regstr_num); - } - sd->regstr[i].index = reg; - sd->regstr[i].data = aStrdup(str); - - return 1; } - -int pc_readregistry(struct map_session_data *sd,const char *reg,int type) -{ - struct global_reg *sd_reg; - int i,max; - - nullpo_ret(sd); - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = sd->save_reg.global_num; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = sd->save_reg.account_num; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = sd->save_reg.account2_num; - break; - default: - return 0; - } - if (max == -1) { - ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type); +/** + * Serves the following variable types: + * - 'type' (permanent nuneric char reg) + * - '#type' (permanent numeric account reg) + * - '##type' (permanent numeric account reg2) + **/ +int pc_readregistry(struct map_session_data *sd, int64 reg) { + struct script_reg_num *p = NULL; + + 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. - intif_request_registry(sd,type==3?4:type); + //intif->request_registry(sd,type==3?4:type); + set_eof(sd->fd); return 0; } + + p = i64db_get(sd->regs.vars, reg); - ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 ); - return ( i < max ) ? atoi(sd_reg[i].value) : 0; + return p ? p->value : 0; } - -char* pc_readregistry_str(struct map_session_data *sd,const char *reg,int type) -{ - struct global_reg *sd_reg; - int i,max; - - nullpo_ret(sd); - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = sd->save_reg.global_num; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = sd->save_reg.account_num; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = sd->save_reg.account2_num; - break; - default: - return NULL; - } - if (max == -1) { - ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type); +/** + * Serves the following variable types: + * - 'type$' (permanent str char reg) + * - '#type$' (permanent str account reg) + * - '##type$' (permanent str account reg2) + **/ +char* pc_readregistry_str(struct map_session_data *sd, int64 reg) { + struct script_reg_str *p = NULL; + + 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. - intif_request_registry(sd,type==3?4:type); + //intif->request_registry(sd,type==3?4:type); + set_eof(sd->fd); return NULL; } - ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 ); - return ( i < max ) ? sd_reg[i].value : NULL; + p = i64db_get(sd->regs.vars, reg); + + return p ? p->value : NULL; } - -int pc_setregistry(struct map_session_data *sd,const char *reg,int val,int type) -{ - struct global_reg *sd_reg; - int i,*max, regmax; - - nullpo_ret(sd); - - switch( type ) - { - case 3: //Char reg - if( !strcmp(reg,"PC_DIE_COUNTER") && sd->die_counter != val ) - { - i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); - sd->die_counter = val; - if( i ) - status_calc_pc(sd,0); // Lost the bonus. - } - else if( !strcmp(reg,"COOK_MASTERY") && sd->cook_mastery != val ) - { - val = cap_value(val, 0, 1999); - sd->cook_mastery = val; - } - sd_reg = sd->save_reg.global; - max = &sd->save_reg.global_num; - regmax = GLOBAL_REG_NUM; - break; - case 2: //Account reg - if( !strcmp(reg,"#CASHPOINTS") && sd->cashPoints != val ) - { - val = cap_value(val, 0, MAX_ZENY); - sd->cashPoints = val; - } - else if( !strcmp(reg,"#KAFRAPOINTS") && sd->kafraPoints != val ) - { - val = cap_value(val, 0, MAX_ZENY); - sd->kafraPoints = val; - } - sd_reg = sd->save_reg.account; - max = &sd->save_reg.account_num; - regmax = ACCOUNT_REG_NUM; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = &sd->save_reg.account2_num; - regmax = ACCOUNT_REG2_NUM; - break; - default: - return 0; +/** + * Serves the following variable types: + * - 'type' (permanent nuneric char reg) + * - '#type' (permanent numeric account reg) + * - '##type' (permanent numeric account reg2) + **/ +int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { + struct script_reg_num *p = NULL; + int i; + const char *regname = script->get_str( script_getvarid(reg) ); + unsigned int index = script_getvaridx(reg); + + /* 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 ) { + i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); + sd->die_counter = val; + if( i ) + status_calc_pc(sd,SCO_NONE); // Lost the bonus. + } else if( !strcmp(regname,"COOK_MASTERY") && sd->cook_mastery != val ) { + val = cap_value(val, 0, 1999); + sd->cook_mastery = val; + } + break; + case '#': + if( !strcmp(regname,"#CASHPOINTS") && sd->cashPoints != val ) { + val = cap_value(val, 0, MAX_ZENY); + sd->cashPoints = val; + } else if( !strcmp(regname,"#KAFRAPOINTS") && sd->kafraPoints != val ) { + val = cap_value(val, 0, MAX_ZENY); + sd->kafraPoints = val; + } + break; } - if (*max == -1) { - ShowError("pc_setregistry : refusing to set %s (type %d) until vars are received.\n", reg, type); - return 1; + + if ( !pc->reg_load && !sd->vars_ok ) { + ShowError("pc_setregistry : refusing to set %s until vars are received.\n", regname); + return 0; } - - // delete reg - if (val == 0) { - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - if (i != *max - 1) - memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg)); - memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg)); - (*max)--; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" + + if( (p = i64db_get(sd->regs.vars, reg) ) ) { + if( val ) { + if( !p->value && index ) /* its a entry that was deleted, so we reset array */ + script->array_update(&sd->regs, reg, false); + p->value = val; + } else { + p->value = 0; + if( index ) + script->array_update(&sd->regs, reg, true); + } + if( !pc->reg_load ) + p->flag.update = 1;/* either way, it will require either delete or replace */ + } else if( val ) { + DBData prev; + + if( index ) + script->array_update(&sd->regs, reg, false); + + p = ers_alloc(pc->num_reg_ers, struct script_reg_num); + + p->value = val; + if( !pc->reg_load ) + p->flag.update = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + ers_free(pc->num_reg_ers, p); } - return 1; } - // change value if found - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val); - sd->state.reg_dirty |= 1<<(type-1); - return 1; - } - - // add value if not found - if (i < regmax) { - memset(&sd_reg[i], 0, sizeof(struct global_reg)); - safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str)); - safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val); - (*max)++; - sd->state.reg_dirty |= 1<<(type-1); - return 1; - } - - ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax); + + if( !pc->reg_load && p ) + sd->vars_dirty = true; - return 0; + return 1; } +/** + * Serves the following variable types: + * - 'type$' (permanent str char reg) + * - '#type$' (permanent str account reg) + * - '##type$' (permanent str account reg2) + **/ +int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) { + struct script_reg_str *p = NULL; + const char *regname = script->get_str( script_getvarid(reg) ); + unsigned int index = script_getvaridx(reg); -int pc_setregistry_str(struct map_session_data *sd,const char *reg,const char *val,int type) -{ - struct global_reg *sd_reg; - int i,*max, regmax; - - nullpo_ret(sd); - if (reg[strlen(reg)-1] != '$') { - ShowError("pc_setregistry_str : reg %s must be string (end in '$') to use this!\n", reg); + if ( !pc->reg_load && !sd->vars_ok ) { + ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname); return 0; } - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = &sd->save_reg.global_num; - regmax = GLOBAL_REG_NUM; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = &sd->save_reg.account_num; - regmax = ACCOUNT_REG_NUM; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = &sd->save_reg.account2_num; - regmax = ACCOUNT_REG2_NUM; - break; - default: - return 0; - } - if (*max == -1) { - ShowError("pc_setregistry_str : refusing to set %s (type %d) until vars are received.\n", reg, type); - return 0; - } - - // delete reg - if (!val || strcmp(val,"")==0) - { - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - if (i != *max - 1) - memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg)); - memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg)); - (*max)--; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); + if( (p = i64db_get(sd->regs.vars, reg) ) ) { + if( val[0] ) { + if( p->value ) + aFree(p->value); + else if ( index ) /* a entry that was deleted, so we reset */ + script->array_update(&sd->regs, reg, false); + p->value = aStrdup(val); + } else { + p->value = NULL; + if( index ) + script->array_update(&sd->regs, reg, true); } - return 1; - } + if( !pc->reg_load ) + p->flag.update = 1;/* either way, it will require either delete or replace */ + } else if( val[0] ) { + DBData prev; - // change value if found - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value)); - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); - return 1; - } + if( index ) + script->array_update(&sd->regs, reg, false); - // add value if not found - if (i < regmax) { - memset(&sd_reg[i], 0, sizeof(struct global_reg)); - safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str)); - safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value)); - (*max)++; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); - return 1; + p = ers_alloc(pc->str_reg_ers, struct script_reg_str); + + p->value = aStrdup(val); + if( !pc->reg_load ) + p->flag.update = 1; + p->flag.type = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + } } - - ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax); - - return 0; + + if( !pc->reg_load && p ) + sd->vars_dirty = true; + + return 1; } /*========================================== * Exec eventtimer for player sd (retrieved from map_session (id)) *------------------------------------------*/ -static int pc_eventtimer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); +int pc_eventtimer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); char *p = (char *)data; int i; if(sd==NULL) @@ -8230,7 +8503,7 @@ static int pc_eventtimer(int tid, unsigned int tick, int id, intptr_t data) { sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; - npc_event(sd,p,0); + npc->event(sd,p,0); } else ShowError("pc_eventtimer: no such event timer\n"); @@ -8251,7 +8524,7 @@ int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name) if( i == MAX_EVENTTIMER ) return 0; - sd->eventtimer[i] = iTimer->add_timer(iTimer->gettick()+tick, pc_eventtimer, sd->bl.id, (intptr_t)aStrdup(name)); + sd->eventtimer[i] = timer->add(timer->gettick()+tick, pc->eventtimer, sd->bl.id, (intptr_t)aStrdup(name)); sd->eventcount++; return 1; @@ -8273,13 +8546,13 @@ int pc_deleventtimer(struct map_session_data *sd,const char *name) // find the named event timer ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] != INVALID_TIMER && - (p = (char *)(iTimer->get_timer(sd->eventtimer[i])->data)) != NULL && + (p = (char *)(timer->get(sd->eventtimer[i])->data)) != NULL && strcmp(p, name) == 0 ); if( i == MAX_EVENTTIMER ) return 0; // not found - iTimer->delete_timer(sd->eventtimer[i],pc_eventtimer); + timer->delete(sd->eventtimer[i],pc->eventtimer); sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; aFree(p); @@ -8298,8 +8571,8 @@ int pc_addeventtimercount(struct map_session_data *sd,const char *name,int tick) for(i=0;i<MAX_EVENTTIMER;i++) if( sd->eventtimer[i] != INVALID_TIMER && strcmp( - (char *)(iTimer->get_timer(sd->eventtimer[i])->data), name)==0 ){ - iTimer->addtick_timer(sd->eventtimer[i],tick); + (char *)(timer->get(sd->eventtimer[i])->data), name)==0 ){ + timer->addtick(sd->eventtimer[i],tick); break; } @@ -8320,8 +8593,8 @@ int pc_cleareventtimer(struct map_session_data *sd) for(i=0;i<MAX_EVENTTIMER;i++) if( sd->eventtimer[i] != INVALID_TIMER ){ - char *p = (char *)(iTimer->get_timer(sd->eventtimer[i])->data); - iTimer->delete_timer(sd->eventtimer[i],pc_eventtimer); + char *p = (char *)(timer->get(sd->eventtimer[i])->data); + timer->delete(sd->eventtimer[i],pc->eventtimer); sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; if (p) aFree(p); @@ -8331,17 +8604,19 @@ int pc_cleareventtimer(struct map_session_data *sd) /* called when a item with combo is worn */ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int i, j, k, z; - int index, idx, success = 0; + int index, success = 0; + struct pc_combos *combo; for( i = 0; i < data->combos_count; i++ ) { /* ensure this isn't a duplicate combo */ - if( sd->combos.bonus != NULL ) { + if( sd->combos != NULL ) { int x; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* found a match, skip this combo */ - if( x < sd->combos.count ) + if( x < sd->combo_count ) continue; } @@ -8358,7 +8633,7 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { if(!sd->inventory_data[index]) continue; - + if ( itemdb_type(id) != IT_CARD ) { if ( sd->inventory_data[index]->nameid != id ) continue; @@ -8392,24 +8667,16 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { /* we got here, means all items in the combo are matching */ - idx = sd->combos.count; - - if( sd->combos.bonus == NULL ) { - CREATE(sd->combos.bonus, struct script_code *, 1); - CREATE(sd->combos.id, unsigned short, 1); - sd->combos.count = 1; - } else { - RECREATE(sd->combos.bonus, struct script_code *, ++sd->combos.count); - RECREATE(sd->combos.id, unsigned short, sd->combos.count); - } - - /* we simply copy the pointer */ - sd->combos.bonus[idx] = data->combos[i]->script; - /* save this combo's id */ - sd->combos.id[idx] = data->combos[i]->id; - + RECREATE(sd->combos, struct pc_combos, ++sd->combo_count); + + combo = &sd->combos[sd->combo_count - 1]; + + combo->bonus = data->combos[i]->script; + combo->id = data->combos[i]->id; + success++; } + return success; } @@ -8417,45 +8684,45 @@ 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; - if( sd->combos.bonus == NULL ) + if( !sd->combos ) return 0;/* nothing to do here, player has no combos */ + for( i = 0; i < data->combos_count; i++ ) { /* check if this combo exists in this user */ int x = 0, cursor = 0, j; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* no match, skip this combo */ - if( !(x < sd->combos.count) ) + if( x == sd->combo_count ) continue; - sd->combos.bonus[x] = NULL; - sd->combos.id[x] = 0; + sd->combos[x].bonus = NULL; + sd->combos[x].id = 0; + retval++; - for( j = 0, cursor = 0; j < sd->combos.count; j++ ) { - if( sd->combos.bonus[j] == NULL ) + + for( j = 0, cursor = 0; j < sd->combo_count; j++ ) { + if( sd->combos[j].bonus == NULL ) continue; if( cursor != j ) { - sd->combos.bonus[cursor] = sd->combos.bonus[j]; - sd->combos.id[cursor] = sd->combos.id[j]; + sd->combos[cursor].bonus = sd->combos[j].bonus; + sd->combos[cursor].id = sd->combos[j].id; } cursor++; } - /* check if combo requirements still fit */ - if( pc_checkcombo( sd, data ) ) - continue; - /* it's empty, we can clear all the memory */ - if( (sd->combos.count = cursor) == 0 ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.bonus = NULL; - sd->combos.id = NULL; - return retval; /* we also can return at this point for we have no more combos to check */ + if( (sd->combo_count = cursor) == 0 ) { + aFree(sd->combos); + sd->combos = NULL; + break; } - } + + /* check if combo requirements still fit -- don't touch retval! */ + pc->checkcombo( sd, data ); return retval; } @@ -8467,16 +8734,16 @@ int pc_load_combo(struct map_session_data *sd) { if( sd->equip_index[i] < 0 || !(id = sd->inventory_data[idx] ) ) continue; if( id->combos_count ) - ret += pc_checkcombo(sd,id); + ret += pc->checkcombo(sd,id); if(!itemdb_isspecial(sd->status.inventory[idx].card[0])) { struct item_data *data; int j; for( j = 0; j < id->slot; j++ ) { if (!sd->status.inventory[idx].card[j]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[idx].card[j]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[idx].card[j]) ) != NULL ) { if( data->combos_count ) - ret += pc_checkcombo(sd,data); + ret += pc->checkcombo(sd,data); } } } @@ -8494,13 +8761,13 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->equipitemack(sd,0,0,0); + clif->equipitemack(sd,0,0,EIA_FAIL); return 0; } - if( DIFF_TICK(sd->canequip_tick,iTimer->gettick()) > 0 ) + if( DIFF_TICK(sd->canequip_tick,timer->gettick()) > 0 ) { - clif->equipitemack(sd,n,0,0); + clif->equipitemack(sd,n,0,EIA_FAIL); return 0; } @@ -8511,27 +8778,38 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) 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] // FIXME: pc->isequip: equip level failure uses 2 instead of 0 - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST]) + if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) { - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } + /* won't fail from this point onwards */ + if( id->flag.bindonequip && !sd->status.inventory[n].bound ) { + sd->status.inventory[n].bound = (unsigned char)IBT_CHARACTER; + clif->notify_bounditem(sd,n); + } + if(pos == EQP_ACC) { //Accesories should only go in one of the two, pos = req_pos&EQP_ACC; if (pos == EQP_ACC) //User specified both slots.. pos = sd->equip_index[EQI_ACC_R] >= 0 ? EQP_ACC_L : EQP_ACC_R; - } - - if(pos == EQP_ARMS && id->equip == EQP_HAND_R) - { //Dual wield capable weapon. + } else if(pos == EQP_ARMS && id->equip == EQP_HAND_R) { //Dual wield capable weapon. pos = (req_pos&EQP_ARMS); if (pos == EQP_ARMS) //User specified both slots, pick one for them. pos = sd->equip_index[EQI_HAND_R] >= 0 ? EQP_HAND_L : EQP_HAND_R; + } else if(pos == EQP_SHADOW_ACC) { //Accesories should only go in one of the two, + pos = req_pos&EQP_SHADOW_ACC; + if (pos == EQP_SHADOW_ACC) //User specified both slots.. + pos = sd->equip_index[EQI_SHADOW_ACC_R] >= 0 ? EQP_SHADOW_ACC_L : EQP_SHADOW_ACC_R; + } else if( pos == EQP_SHADOW_ARMS && id->equip == EQP_SHADOW_WEAPON) { //Dual wield capable weapon. + pos = (req_pos&EQP_SHADOW_ARMS); + if (pos == EQP_SHADOW_ARMS) //User specified both slots, pick one for them. + pos = sd->equip_index[EQI_SHADOW_WEAPON] >= 0 ? EQP_SHADOW_SHIELD : EQP_SHADOW_WEAPON; } if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) @@ -8544,7 +8822,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) } for(i=0;i<EQI_MAX;i++) { - if(pos & equip_pos[i]) { + if(pos & pc->equip_pos[i]) { if(sd->equip_index[i] >= 0) //Slot taken, remove item from there. pc->unequipitem(sd,sd->equip_index[i],2); @@ -8557,33 +8835,30 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) clif->arrow_fail(sd,3); } else - clif->equipitemack(sd,n,pos,1); + clif->equipitemack(sd,n,pos,EIA_SUCCESS); sd->status.inventory[n].equip=pos; - if(pos & EQP_HAND_R) { + if(pos & (EQP_HAND_R|EQP_SHADOW_WEAPON)) { if(id) sd->weapontype1 = id->look; else sd->weapontype1 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); } - if(pos & EQP_HAND_L) { + if(pos & (EQP_HAND_L|EQP_SHADOW_SHIELD)) { if(id) { if(id->type == IT_WEAPON) { sd->status.shield = 0; sd->weapontype2 = id->look; - } - else - if(id->type == IT_ARMOR) { + } else if(id->type == IT_ARMOR) { sd->status.shield = id->look; sd->weapontype2 = 0; } - } - else + } else sd->status.shield = sd->weapontype2 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield); } //Added check to prevent sending the same look on multiple slots -> @@ -8650,7 +8925,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) /* check for combos (MUST be before status_calc_pc) */ if ( id ) { if( id->combos_count ) - pc_checkcombo(sd,id); + pc->checkcombo(sd,id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8658,22 +8933,22 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->combos_count ) - pc_checkcombo(sd,data); + pc->checkcombo(sd,data); } } } } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); if (flag) //Update skill data clif->skillinfoblock(sd); //OnEquip script [Skotlex] if (id) { if (id->equip_script) - run_script(id->equip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(id->equip_script,0,sd->bl.id,npc->fake_nd->bl.id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8681,9 +8956,9 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->equip_script ) - run_script(data->equip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(data->equip_script,0,sd->bl.id,npc->fake_nd->bl.id); } } } @@ -8706,20 +8981,20 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->unequipitemack(sd,0,0,0); + clif->unequipitemack(sd,0,0,UIA_FAIL); return 0; } // if player is berserk then cannot unequip - if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST])) + if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) ) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } if( !(flag&2) && sd->sc.count && sd->sc.data[SC_KYOUGAKU] ) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } @@ -8727,25 +9002,25 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { ShowInfo("unequip %d %x:%x\n",n,pc->equippoint(sd,n),sd->status.inventory[n].equip); if(!sd->status.inventory[n].equip){ //Nothing to unequip - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } for(i=0;i<EQI_MAX;i++) { - if(sd->status.inventory[n].equip & equip_pos[i]) + if(sd->status.inventory[n].equip & pc->equip_pos[i]) sd->equip_index[i] = -1; } if(sd->status.inventory[n].equip & EQP_HAND_R) { sd->weapontype1 = 0; sd->status.weapon = sd->weapontype2; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); if( !battle_config.dancing_weaponswitch_fix ) status_change_end(&sd->bl, SC_DANCING, INVALID_TIMER); // Unequipping => stop dancing. } if(sd->status.inventory[n].equip & EQP_HAND_L) { sd->status.shield = sd->weapontype2 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield); } if(sd->status.inventory[n].equip & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1 ) { @@ -8789,7 +9064,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { clif->changelook(&sd->bl,LOOK_ROBE,sd->status.robe); } - clif->unequipitemack(sd,n,sd->status.inventory[n].equip,1); + clif->unequipitemack(sd,n,sd->status.inventory[n].equip,UIA_SUCCESS); if((sd->status.inventory[n].equip & 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!) @@ -8810,7 +9085,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int 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]) ) + if( pc->removecombo(sd,sd->inventory_data[n]) ) status_cacl = true; } if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards @@ -8819,9 +9094,9 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->combos_count ) { - if( pc_removecombo(sd,data) ) + if( pc->removecombo(sd,data) ) status_cacl = true; } } @@ -8831,7 +9106,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { if(flag&1 || status_cacl) { pc->checkallowskill(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } if(sd->sc.data[SC_CRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele)) @@ -8840,7 +9115,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { //OnUnEquip script [Skotlex] if (sd->inventory_data[n]) { if (sd->inventory_data[n]->unequip_script) - run_script(sd->inventory_data[n]->unequip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(sd->inventory_data[n]->unequip_script,0,sd->bl.id,npc->fake_nd->bl.id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8849,9 +9124,9 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->unequip_script ) - run_script(data->unequip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(data->unequip_script,0,sd->bl.id,npc->fake_nd->bl.id); } } @@ -8868,31 +9143,85 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { *------------------------------------------*/ int pc_checkitem(struct map_session_data *sd) { - int i,id,calc_flag = 0; + int i, id, calc_flag = 0; 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) return 0; - if( battle_config.item_check ) { // check for invalid(ated) items + if( sd->state.itemcheck ) { // check for invalid(ated) items for( i = 0; i < MAX_INVENTORY; i++ ) { id = sd->status.inventory[i].nameid; - if( id && !itemdb_available(id) ) { + if (!id) + 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, 0, LOG_TYPE_OTHER); + continue; } + + if ( !sd->status.inventory[i].unique_id && !itemdb->isstackable(id) ) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); } for( i = 0; i < MAX_CART; i++ ) { id = sd->status.cart[i].nameid; - if( id && !itemdb_available(id) ) { + if (!id) + 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 && !itemdb->isstackable(id) ) + sd->status.cart[i].unique_id = itemdb->unique_id(sd); + } + + for( i = 0; i < MAX_STORAGE; i++ ) { + id = sd->status.storage.items[i].nameid; + + if (!id) + 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 ( !sd->status.storage.items[i].unique_id && !itemdb->isstackable(id) ) + sd->status.storage.items[i].unique_id = itemdb->unique_id(sd); } + + if (sd->guild) { + struct guild_storage *guild_storage = gstorage->id2storage2(sd->guild->guild_id); + if (guild_storage) { + for( i = 0; i < MAX_GUILD_STORAGE; i++ ) { + id = guild_storage->items[i].nameid; + + if (!id) + 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); + 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)) + guild_storage->items[i].unique_id = itemdb->unique_id(sd); + } + } + } + sd->state.itemcheck = 0; } for( i = 0; i < MAX_INVENTORY; i++) { @@ -8910,10 +9239,10 @@ int pc_checkitem(struct map_session_data *sd) } } - + if( calc_flag && sd->state.active ) { pc->checkallowskill(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } return 0; @@ -8939,17 +9268,16 @@ int pc_calc_pvprank_sub(struct block_list *bl,va_list ap) return 0; } /*========================================== - * Calculate new rank beetween all present players (iMap->foreachinarea) + * Calculate new rank beetween all present players (map->foreachinarea) * and display result *------------------------------------------*/ -int pc_calc_pvprank(struct map_session_data *sd) -{ +int pc_calc_pvprank(struct map_session_data *sd) { int old; struct map_data *m; - m=&map[sd->bl.m]; + m=&map->list[sd->bl.m]; old=sd->pvp_rank; sd->pvp_rank=1; - iMap->foreachinmap(pc_calc_pvprank_sub,sd->bl.m,BL_PC,sd); + map->foreachinmap(pc_calc_pvprank_sub,sd->bl.m,BL_PC,sd); if(old!=sd->pvp_rank || sd->pvp_lastusers!=m->users_pvp) clif->pvpset(sd,sd->pvp_rank,sd->pvp_lastusers=m->users_pvp,0); return sd->pvp_rank; @@ -8957,11 +9285,10 @@ int pc_calc_pvprank(struct map_session_data *sd) /*========================================== * Calculate next sd ranking calculation from config *------------------------------------------*/ -int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_calc_pvprank_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; - sd=iMap->id2sd(id); + sd=map->id2sd(id); if(sd==NULL) return 0; sd->pvp_timer = INVALID_TIMER; @@ -8972,7 +9299,7 @@ int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data) } if( pc->calc_pvprank(sd) > 0 ) - sd->pvp_timer = iTimer->add_timer(iTimer->gettick()+PVP_CALCRANK_INTERVAL,pc->calc_pvprank_timer,id,data); + sd->pvp_timer = timer->add(timer->gettick()+PVP_CALCRANK_INTERVAL,pc->calc_pvprank_timer,id,data); return 0; } @@ -9025,9 +9352,9 @@ int pc_divorce(struct map_session_data *sd) if( !sd->status.partner_id ) return -1; // Char is not married - if( (p_sd = iMap->charid2sd(sd->status.partner_id)) == NULL ) - { // Lets char server do the divorce - if( chrif_divorce(sd->status.char_id, sd->status.partner_id) ) + if( (p_sd = map->charid2sd(sd->status.partner_id)) == NULL ) { + // Lets char server do the divorce + if( chrif->divorce(sd->status.char_id, sd->status.partner_id) ) return -1; // No char server connected return 0; @@ -9053,11 +9380,10 @@ int pc_divorce(struct map_session_data *sd) /*========================================== * Get sd partner charid. (Married partner) *------------------------------------------*/ -struct map_session_data *pc_get_partner(struct map_session_data *sd) -{ +struct map_session_data *pc_get_partner(struct map_session_data *sd) { if (sd && pc->ismarried(sd)) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.partner_id); + return map->charid2sd(sd->status.partner_id); return NULL; } @@ -9065,11 +9391,10 @@ 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) -{ +struct map_session_data *pc_get_father(struct map_session_data *sd) { if (sd && sd->class_&JOBL_BABY && sd->status.father > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.father); + return map->charid2sd(sd->status.father); return NULL; } @@ -9077,11 +9402,10 @@ 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) -{ +struct map_session_data *pc_get_mother(struct map_session_data *sd) { if (sd && sd->class_&JOBL_BABY && sd->status.mother > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.mother); + return map->charid2sd(sd->status.mother); return NULL; } @@ -9089,11 +9413,10 @@ struct map_session_data *pc_get_mother (struct map_session_data *sd) /*========================================== * Get sd children charid. (Need to be married) *------------------------------------------*/ -struct map_session_data *pc_get_child (struct map_session_data *sd) -{ +struct map_session_data *pc_get_child(struct map_session_data *sd) { if (sd && pc->ismarried(sd) && sd->status.child > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.child); + return map->charid2sd(sd->status.child); return NULL; } @@ -9135,8 +9458,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) //Character regen. Flag is used to know which types of regen can take place. //&1: HP regen //&2: SP regen -void pc_regen (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; if (sd->hp_regen.value) { @@ -9156,7 +9478,7 @@ void pc_regen (struct map_session_data *sd, unsigned int diff_tick) } if (hp > 0 || sp > 0) - status_heal(&sd->bl, hp, sp, 0); + status->heal(&sd->bl, hp, sp, 0); return; } @@ -9164,11 +9486,10 @@ void pc_regen (struct map_session_data *sd, unsigned int diff_tick) /*========================================== * Memo player sd savepoint. (map,x,y) *------------------------------------------*/ -int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y) -{ +int pc_setsavepoint(struct map_session_data *sd, short map_index, int x, int y) { nullpo_ret(sd); - sd->status.save_point.map = mapindex; + sd->status.save_point.map = map_index; sd->status.save_point.x = x; sd->status.save_point.y = y; @@ -9176,10 +9497,9 @@ int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y) } /*========================================== - * Save 1 player data at autosave intervalle + * Save 1 player data at autosave intervall *------------------------------------------*/ -int pc_autosave(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_autosave(int tid, int64 tick, int id, intptr_t data) { int interval; struct s_mapiterator* iter; struct map_session_data* sd; @@ -9205,24 +9525,23 @@ int pc_autosave(int tid, unsigned int tick, int id, intptr_t data) last_save_id = sd->bl.id; save_flag = 2; - chrif_save(sd,0); + chrif->save(sd,0); break; } mapit->free(iter); - interval = iMap->autosave_interval/(iMap->usercount()+1); - if(interval < iMap->minsave_interval) - interval = iMap->minsave_interval; - iTimer->add_timer(iTimer->gettick()+interval,pc_autosave,0,0); + interval = map->autosave_interval/(map->usercount()+1); + if(interval < map->minsave_interval) + interval = map->minsave_interval; + timer->add(timer->gettick()+interval,pc->autosave,0,0); return 0; } -static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) -{ - if (sd->state.night != iMap->night_flag && map[sd->bl.m].flag.nightenabled) { //Night/day state does not match. - clif->status_change(&sd->bl, SI_SKE, iMap->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] - sd->state.night = iMap->night_flag; +int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) { + 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; return 1; } return 0; @@ -9231,20 +9550,19 @@ static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) * timer to do the day [Yor] * data: 0 = called by timer, 1 = gmcommand/script *------------------------------------------------*/ -int map_day_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int map_day_timer(int tid, int64 tick, int id, intptr_t data) { char tmp_soutput[1024]; - if (data == 0 && battle_config.day_duration <= 0) // if we want a day + if (data == 0 && battle_config.day_duration <= 0) // if we want a day return 0; - if (!iMap->night_flag) + if (!map->night_flag) return 0; //Already day. - iMap->night_flag = 0; // 0=day, 1=night [Yor] - iMap->map_foreachpc(pc_daynight_timer_sub); + map->night_flag = 0; // 0=day, 1=night [Yor] + map->foreachpc(pc->daynight_timer_sub); strcpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60)); // The day has arrived! - intif_broadcast(tmp_soutput, strlen(tmp_soutput) + 1, 0); + intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -9252,24 +9570,23 @@ int map_day_timer(int tid, unsigned int tick, int id, intptr_t data) * timer to do the night [Yor] * data: 0 = called by timer, 1 = gmcommand/script *------------------------------------------------*/ -int map_night_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int map_night_timer(int tid, int64 tick, int id, intptr_t data) { char tmp_soutput[1024]; - if (data == 0 && battle_config.night_duration <= 0) // if we want a night + if (data == 0 && battle_config.night_duration <= 0) // if we want a night return 0; - if (iMap->night_flag) + if (map->night_flag) return 0; //Already nigth. - iMap->night_flag = 1; // 0=day, 1=night [Yor] - iMap->map_foreachpc(pc_daynight_timer_sub); + map->night_flag = 1; // 0=day, 1=night [Yor] + map->foreachpc(pc->daynight_timer_sub); strcpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59)); // The night has fallen... - intif_broadcast(tmp_soutput, strlen(tmp_soutput) + 1, 0); + intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } -void pc_setstand(struct map_session_data *sd){ +void pc_setstand(struct map_session_data *sd) { nullpo_retv(sd); status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER); @@ -9283,23 +9600,23 @@ void pc_setstand(struct map_session_data *sd){ * Mechanic (MADO GEAR) **/ void pc_overheat(struct map_session_data *sd, int val) { - int heat = val, skill, + int heat = val, skill_lv, limit[] = { 10, 20, 28, 46, 66 }; if( !pc_ismadogear(sd) || sd->sc.data[SC_OVERHEAT] ) return; // already burning - skill = cap_value(pc->checkskill(sd,NC_MAINFRAME),0,4); + skill_lv = cap_value(pc->checkskill(sd,NC_MAINFRAME),0,4); if( sd->sc.data[SC_OVERHEAT_LIMITPOINT] ) { heat += sd->sc.data[SC_OVERHEAT_LIMITPOINT]->val1; status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER); } heat = max(0,heat); // Avoid negative HEAT - if( heat >= limit[skill] ) - sc_start(&sd->bl,SC_OVERHEAT,100,0,1000); + if( heat >= limit[skill_lv] ) + sc_start(NULL,&sd->bl,SC_OVERHEAT,100,0,1000); else - sc_start(&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000); + sc_start(NULL,&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000); return; } @@ -9309,10 +9626,16 @@ void pc_overheat(struct map_session_data *sd, int val) { */ bool pc_isautolooting(struct map_session_data *sd, int nameid) { - int i; - if( !sd->state.autolooting ) + int i = 0; + + if (sd->state.autoloottype && sd->state.autoloottype&(1<<itemdb_type(nameid))) + return true; + + if (!sd->state.autolooting) return false; + ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == nameid); + return (i != AUTOLOOTITEM_SIZE); } @@ -9325,12 +9648,11 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command) { return atcommand->can_use(sd,command); } -static int pc_charm_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_charm_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; int i, type; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; ARR_FIND(1, 5, type, sd->charm[type] > 0); @@ -9373,15 +9695,15 @@ int pc_add_charm(struct map_session_data *sd,int interval,int max,int type) if( sd->charm[type] && sd->charm[type] >= max ) { if(sd->charm_timer[type][0] != INVALID_TIMER) - iTimer->delete_timer(sd->charm_timer[type][0],pc_charm_timer); + timer->delete(sd->charm_timer[type][0],pc->charm_timer); sd->charm[type]--; if( sd->charm[type] != 0 ) memmove(sd->charm_timer[type]+0, sd->charm_timer[type]+1, (sd->charm[type])*sizeof(int)); sd->charm_timer[type][sd->charm[type]] = INVALID_TIMER; } - tid = iTimer->add_timer(iTimer->gettick()+interval, pc_charm_timer, sd->bl.id, 0); - ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick, iTimer->get_timer(sd->charm_timer[type][i])->tick) < 0); + tid = timer->add(timer->gettick()+interval, pc->charm_timer, sd->bl.id, 0); + ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->charm_timer[type][i])->tick) < 0); if( i != sd->charm[type] ) memmove(sd->charm_timer[type]+i+1, sd->charm_timer[type]+i, (sd->charm[type]-i)*sizeof(int)); sd->charm_timer[type][i] = tid; @@ -9412,7 +9734,7 @@ int pc_del_charm(struct map_session_data *sd,int count,int type) for(i = 0; i < count; i++) { if(sd->charm_timer[type][i] != INVALID_TIMER) { - iTimer->delete_timer(sd->charm_timer[type][i],pc_charm_timer); + timer->delete(sd->charm_timer[type][i],pc->charm_timer); sd->charm_timer[type][i] = INVALID_TIMER; } } @@ -9424,19 +9746,13 @@ int pc_del_charm(struct map_session_data *sd,int count,int type) clif->charm(sd, type); return 0; } -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) /*========================================== * Renewal EXP/Itemdrop rate modifier base on level penalty * 1=exp 2=itemdrop *------------------------------------------*/ -int pc_level_penalty_mod(struct map_session_data *sd, struct mob_data *md, int type) -{ - int diff, rate = 100, i; - - nullpo_ret(sd); - nullpo_ret(md); - - diff = md->level - sd->status.base_level; +int pc_level_penalty_mod(int diff, unsigned char race, unsigned short mode, int type) { +#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) + int rate = 100, i; if( diff < 0 ) diff = MAX_LEVEL + ( ~diff + 1 ); @@ -9444,22 +9760,24 @@ int pc_level_penalty_mod(struct map_session_data *sd, struct mob_data *md, int t for(i=0; i<RC_MAX; i++){ int tmp; - if( md->status.race != i ){ - if( md->status.mode&MD_BOSS && i < RC_BOSS ) + if( race != i ){ + if( mode&MD_BOSS && i < RC_BOSS ) i = RC_BOSS; else if( i <= RC_BOSS ) continue; } - if( (tmp=level_penalty[type][i][diff]) > 0 ){ + if( (tmp=pc->level_penalty[type][i][diff]) > 0 ){ rate = tmp; break; } } return rate; -} +#else + return 100; #endif +} int pc_split_str(char *str,char **val,int num) { int i; @@ -9516,59 +9834,271 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) val[j] = 0; return i; } +/* [Ind/Hercules] */ +void pc_read_skill_tree(void) { + config_t skill_tree_conf; + config_setting_t *skt = NULL, *inherit = NULL, *skills = NULL, *sk = NULL; +#ifdef RENEWAL + const char *config_filename = "db/re/skill_tree.conf"; // FIXME hardcoded name +#else + const char *config_filename = "db/pre-re/skill_tree.conf"; // FIXME hardcoded name +#endif + int i = 0, jnamelen = 0; + struct s_mapiterator *iter; + struct map_session_data *sd; + struct { + const char *name; + int id; + } jnames[] = { + { "Novice", JOB_NOVICE }, + { "Swordsman", JOB_SWORDMAN }, + { "Magician", JOB_MAGE }, + { "Archer", JOB_ARCHER }, + { "Acolyte", JOB_ACOLYTE }, + { "Merchant", JOB_MERCHANT }, + { "Thief", JOB_THIEF }, + { "Knight", JOB_KNIGHT }, + { "Priest", JOB_PRIEST }, + { "Wizard", JOB_WIZARD }, + { "Blacksmith", JOB_BLACKSMITH }, + { "Hunter", JOB_HUNTER }, + { "Assassin", JOB_ASSASSIN }, + { "Crusader", JOB_CRUSADER }, + { "Monk", JOB_MONK }, + { "Sage", JOB_SAGE }, + { "Rogue", JOB_ROGUE }, + { "Alchemist", JOB_ALCHEMIST }, + { "Bard", JOB_BARD }, + { "Dancer", JOB_DANCER }, + { "Super_Novice", JOB_SUPER_NOVICE }, + { "Gunslinger", JOB_GUNSLINGER }, + { "Ninja", JOB_NINJA }, + { "Novice_High", JOB_NOVICE_HIGH }, + { "Swordsman_High", JOB_SWORDMAN_HIGH }, + { "Magician_High", JOB_MAGE_HIGH }, + { "Archer_High", JOB_ARCHER_HIGH }, + { "Acolyte_High", JOB_ACOLYTE_HIGH }, + { "Merchant_High", JOB_MERCHANT_HIGH }, + { "Thief_High", JOB_THIEF_HIGH }, + { "Lord_Knight", JOB_LORD_KNIGHT }, + { "High_Priest", JOB_HIGH_PRIEST }, + { "High_Wizard", JOB_HIGH_WIZARD }, + { "Whitesmith", JOB_WHITESMITH }, + { "Sniper", JOB_SNIPER }, + { "Assassin_Cross", JOB_ASSASSIN_CROSS }, + { "Paladin", JOB_PALADIN }, + { "Champion", JOB_CHAMPION }, + { "Professor", JOB_PROFESSOR }, + { "Stalker", JOB_STALKER }, + { "Creator", JOB_CREATOR }, + { "Clown", JOB_CLOWN }, + { "Gypsy", JOB_GYPSY }, + { "Baby_Novice", JOB_BABY }, + { "Baby_Swordsman", JOB_BABY_SWORDMAN }, + { "Baby_Magician", JOB_BABY_MAGE }, + { "Baby_Archer", JOB_BABY_ARCHER }, + { "Baby_Acolyte", JOB_BABY_ACOLYTE }, + { "Baby_Merchant", JOB_BABY_MERCHANT }, + { "Baby_Thief", JOB_BABY_THIEF }, + { "Baby_Knight", JOB_BABY_KNIGHT }, + { "Baby_Priest", JOB_BABY_PRIEST }, + { "Baby_Wizard", JOB_BABY_WIZARD }, + { "Baby_Blacksmith", JOB_BABY_BLACKSMITH }, + { "Baby_Hunter", JOB_BABY_HUNTER }, + { "Baby_Assassin", JOB_BABY_ASSASSIN }, + { "Baby_Crusader", JOB_BABY_CRUSADER }, + { "Baby_Monk", JOB_BABY_MONK }, + { "Baby_Sage", JOB_BABY_SAGE }, + { "Baby_Rogue", JOB_BABY_ROGUE }, + { "Baby_Alchemist", JOB_BABY_ALCHEMIST }, + { "Baby_Bard", JOB_BABY_BARD }, + { "Baby_Dancer", JOB_BABY_DANCER }, + { "Super_Baby", JOB_SUPER_BABY }, + { "Taekwon", JOB_TAEKWON }, + { "Star_Gladiator", JOB_STAR_GLADIATOR }, + { "Soul_Linker", JOB_SOUL_LINKER }, + { "Gangsi", JOB_GANGSI }, + { "Death_Knight", JOB_DEATH_KNIGHT }, + { "Dark_Collector", JOB_DARK_COLLECTOR }, + { "Rune_Knight", JOB_RUNE_KNIGHT }, + { "Warlock", JOB_WARLOCK }, + { "Ranger", JOB_RANGER }, + { "Arch_Bishop", JOB_ARCH_BISHOP }, + { "Mechanic", JOB_MECHANIC }, + { "Guillotine_Cross", JOB_GUILLOTINE_CROSS }, + { "Rune_Knight_Trans", JOB_RUNE_KNIGHT_T }, + { "Warlock_Trans", JOB_WARLOCK_T }, + { "Ranger_Trans", JOB_RANGER_T }, + { "Arch_Bishop_Trans", JOB_ARCH_BISHOP_T }, + { "Mechanic_Trans", JOB_MECHANIC_T }, + { "Guillotine_Cross_Trans", JOB_GUILLOTINE_CROSS_T }, + { "Royal_Guard", JOB_ROYAL_GUARD }, + { "Sorcerer", JOB_SORCERER }, + { "Minstrel", JOB_MINSTREL }, + { "Wanderer", JOB_WANDERER }, + { "Sura", JOB_SURA }, + { "Genetic", JOB_GENETIC }, + { "Shadow_Chaser", JOB_SHADOW_CHASER }, + { "Royal_Guard_Trans", JOB_ROYAL_GUARD_T }, + { "Sorcerer_Trans", JOB_SORCERER_T }, + { "Minstrel_Trans", JOB_MINSTREL_T }, + { "Wanderer_Trans", JOB_WANDERER_T }, + { "Sura_Trans", JOB_SURA_T }, + { "Genetic_Trans", JOB_GENETIC_T }, + { "Shadow_Chaser_Trans", JOB_SHADOW_CHASER_T }, + { "Baby_Rune_Knight", JOB_BABY_RUNE }, + { "Baby_Warlock", JOB_BABY_WARLOCK }, + { "Baby_Ranger", JOB_BABY_RANGER }, + { "Baby_Arch_Bishop", JOB_BABY_BISHOP }, + { "Baby_Mechanic", JOB_BABY_MECHANIC }, + { "Baby_Guillotine_Cross", JOB_BABY_CROSS }, + { "Baby_Royal_Guard", JOB_BABY_GUARD }, + { "Baby_Sorcerer", JOB_BABY_SORCERER }, + { "Baby_Minstrel", JOB_BABY_MINSTREL }, + { "Baby_Wanderer", JOB_BABY_WANDERER }, + { "Baby_Sura", JOB_BABY_SURA }, + { "Baby_Genetic", JOB_BABY_GENETIC }, + { "Baby_Shadow_Chaser", JOB_BABY_CHASER }, + { "Expanded_Super_Novice", JOB_SUPER_NOVICE_E }, + { "Expanded_Super_Baby", JOB_SUPER_BABY_E }, + { "Kagerou", JOB_KAGEROU }, + { "Oboro", JOB_OBORO }, + { "Rebellion", JOB_REBELLION }, + }; + + if (libconfig->read_file(&skill_tree_conf, config_filename)) { + ShowError("can't read %s\n", config_filename); + return; + } + + jnamelen = ARRAYLENGTH(jnames); + + while( (skt = libconfig->setting_get_elem(skill_tree_conf.root,i++)) ) { + int k, idx; + const char *name = config_setting_name(skt); + + ARR_FIND(0, jnamelen, k, strcmpi(jnames[k].name,name) == 0 ); + + if( k == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n",name); + continue; + } + + + if( ( skills = libconfig->setting_get_member(skt,"skills") ) ) { + int c = 0; + + idx = pc->class2idx(jnames[k].id); + + while( ( sk = libconfig->setting_get_elem(skills,c++) ) ) { + const char *sk_name = config_setting_name(sk); + int skill_id; + + if( ( skill_id = skill->name2id(sk_name) ) ) { + int skidx, offset = 0, h = 0, rlen = 0, rskid = 0; + + ARR_FIND( 0, MAX_SKILL_TREE, skidx, pc->skill_tree[idx][skidx].id == 0 || pc->skill_tree[idx][skidx].id == skill_id ); + if (skidx == MAX_SKILL_TREE) { + ShowWarning("pc_read_skill_tree: Unable to load skill %d (%s) into '%s's tree. Maximum number of skills per class has been reached.\n", skill_id, sk_name, name); + continue; + } else if (pc->skill_tree[idx][skidx].id) { + ShowNotice("pc_read_skill_tree: Overwriting %d for '%s' (%d)\n", skill_id, name, jnames[k].id); + } + + pc->skill_tree[idx][skidx].id = skill_id; + pc->skill_tree[idx][skidx].idx = skill->get_index(skill_id); + + if( config_setting_is_group(sk) ) { + int max = 0, jlevel = 0; + libconfig->setting_lookup_int(sk, "MaxLevel", &max); + libconfig->setting_lookup_int(sk, "MinJobLevel", &jlevel); + pc->skill_tree[idx][skidx].max = (unsigned char)max; + pc->skill_tree[idx][skidx].joblv = (unsigned char)jlevel; + rlen = libconfig->setting_length(sk); + offset += jlevel ? 2 : 1; + } else { + pc->skill_tree[idx][skidx].max = (unsigned char)libconfig->setting_get_int(sk); + pc->skill_tree[idx][skidx].joblv = 0; + } + + for( h = offset; h < rlen && h < MAX_PC_SKILL_REQUIRE; h++ ) { + config_setting_t *rsk = libconfig->setting_get_elem(sk,h); + if( rsk && ( rskid = skill->name2id(config_setting_name(rsk)) ) ) { + pc->skill_tree[idx][skidx].need[h].id = rskid; + pc->skill_tree[idx][skidx].need[h].idx = skill->get_index(rskid); + pc->skill_tree[idx][skidx].need[h].lv = (unsigned char)libconfig->setting_get_int(rsk); + } else if( rsk ) { + ShowWarning("pc_read_skill_tree: unknown requirement '%s' for '%s' in '%s'\n",config_setting_name(rsk),sk_name,name); + } else { + ShowWarning("pc_read_skill_tree: error for '%s' in '%s'\n",sk_name,name); + } + } + + } else { + ShowWarning("pc_read_skill_tree: unknown skill '%s' in '%s'\n",sk_name,name); + } + } + } + } + + i = 0; + while( (skt = libconfig->setting_get_elem(skill_tree_conf.root,i++)) ) { + int k, idx, v = 0; + const char *name = config_setting_name(skt); + const char *iname; -/*========================================== - * sub DB reading. - * Function used to read skill_tree.txt - *------------------------------------------*/ -static bool pc_readdb_skilltree(char* fields[], int columns, int current) -{ - unsigned char joblv = 0, skill_lv; - uint16 skill_id; - int idx, class_; - unsigned int i, offset = 3, skill_idx; + + ARR_FIND(0, jnamelen, k, strcmpi(jnames[k].name,name) == 0 ); + + if( k == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n",name); + continue; + } + idx = pc->class2idx(jnames[k].id); - class_ = atoi(fields[0]); - skill_id = (uint16)atoi(fields[1]); - skill_lv = (unsigned char)atoi(fields[2]); + if( ( inherit = libconfig->setting_get_member(skt,"inherit") ) ) { + while( ( iname = libconfig->setting_get_string_elem(inherit, v++) ) ) { + int b = 0, a, d, f, fidx; - if(columns==4+MAX_PC_SKILL_REQUIRE*2) - {// job level requirement extra column - joblv = (unsigned char)atoi(fields[3]); - offset++; - } + ARR_FIND(0, jnamelen, b, strcmpi(jnames[b].name,iname) == 0 ); + + if( b == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' trying to inherit unknown '%s'!\n",name,iname); + continue; + } + + fidx = pc->class2idx(jnames[b].id); + + ARR_FIND( 0, MAX_SKILL_TREE, d, pc->skill_tree[fidx][d].id == 0 ); - if(!pcdb_checkid(class_)) - { - ShowWarning("pc_readdb_skilltree: Invalid job class %d specified.\n", class_); - return false; - } - idx = pc->class2idx(class_); + for( f = 0; f < d; f++ ) { + + ARR_FIND( 0, MAX_SKILL_TREE, a, pc->skill_tree[idx][a].id == 0 || pc->skill_tree[idx][a].id == pc->skill_tree[fidx][f].id ); - //This is to avoid adding two lines for the same skill. [Skotlex] - ARR_FIND( 0, MAX_SKILL_TREE, skill_idx, skill_tree[idx][skill_idx].id == 0 || skill_tree[idx][skill_idx].id == skill_id ); - if( skill_idx == MAX_SKILL_TREE ) { - ShowWarning("pc_readdb_skilltree: Unable to load skill %hu into job %d's tree. Maximum number of skills per class has been reached.\n", skill_id, class_); - return false; - } else if(skill_tree[idx][skill_idx].id) { - ShowNotice("pc_readdb_skilltree: Overwriting skill %hu for job class %d.\n", skill_id, class_); + 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|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])); + } + + } + } + } + + libconfig->destroy(&skill_tree_conf); - skill_tree[idx][skill_idx].id = skill_id; - skill_tree[idx][skill_idx].idx = skill->get_index(skill_id); - skill_tree[idx][skill_idx].max = skill_lv; - skill_tree[idx][skill_idx].joblv = joblv; - - for(i = 0; i < MAX_PC_SKILL_REQUIRE; i++) { - skill_tree[idx][skill_idx].need[i].id = atoi(fields[i*2+offset]); - skill_tree[idx][skill_idx].need[i].idx = skill->get_index(atoi(fields[i*2+offset])); - skill_tree[idx][skill_idx].need[i].lv = atoi(fields[i*2+offset+1]); - } - return true; + /* lets update all players skill tree */ + iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) + clif->skillinfoblock(sd); + mapit->free(iter); } +bool pc_readdb_levelpenalty(char* fields[], int columns, int current) { #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) -{ int type, race, diff; type = atoi(fields[0]); @@ -9590,11 +10120,10 @@ static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) if( diff < 0 ) diff = min(MAX_LEVEL + ( ~(diff) + 1 ), MAX_LEVEL*2); - level_penalty[type][race][diff] = atoi(fields[3]); - + pc->level_penalty[type][race][diff] = atoi(fields[3]); +#endif return true; } -#endif /*========================================== * pc DB reading. @@ -9602,26 +10131,24 @@ static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) * skill_tree.txt - skill tree for every class * attr_fix.txt - elemental adjustment table *------------------------------------------*/ -int pc_readdb(void) -{ +int pc_readdb(void) { int i,j,k; unsigned int count = 0; FILE *fp; char line[24000],*p; - //reset - memset(exp_table,0,sizeof(exp_table)); - memset(max_level,0,sizeof(max_level)); + //reset + memset(pc->exp_table,0,sizeof(pc->exp_table)); + memset(pc->max_level,0,sizeof(pc->max_level)); - sprintf(line, "%s/"DBPATH"exp.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"exp.txt", map->db_path); fp=fopen(line, "r"); if(fp==NULL){ ShowError("can't read %s\n", line); return 1; } - while(fgets(line, sizeof(line), fp)) - { + while(fgets(line, sizeof(line), fp)) { int jobs[CLASS_COUNT], job_count, job, job_id; int type; unsigned int ui,maxlv; @@ -9652,23 +10179,23 @@ int pc_readdb(void) count++; job = jobs[0] = pc->class2idx(job_id); //We send one less and then one more because the last entry in the exp array should hold 0. - max_level[job][type] = pc_split_atoui(split[3], exp_table[job][type],',',maxlv-1)+1; + pc->max_level[job][type] = pc_split_atoui(split[3], pc->exp_table[job][type],',',maxlv-1)+1; //Reverse check in case the array has a bunch of trailing zeros... [Skotlex] //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 = max_level[job][type]) >= 2 && exp_table[job][type][ui-2] <= 0) - max_level[job][type]--; - if (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, max_level[job][type]); + while ((ui = pc->max_level[job][type]) >= 2 && pc->exp_table[job][type][ui-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]); ShowInfo("Filling the missing values with the last exp entry.\n"); //Fill the requested values with the last entry. - ui = (max_level[job][type] <= 2? 0: max_level[job][type]-2); + ui = (pc->max_level[job][type] <= 2? 0: pc->max_level[job][type]-2); for (; ui+2 < maxlv; ui++) - exp_table[job][type][ui] = exp_table[job][type][ui-1]; - max_level[job][type] = maxlv; + pc->exp_table[job][type][ui] = pc->exp_table[job][type][ui-1]; + pc->max_level[job][type] = maxlv; } -// ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, max_level[job][type]); +// ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]); for (i = 1; i < job_count; i++) { job_id = jobs[i]; if (!pcdb_checkid(job_id)) { @@ -9676,9 +10203,9 @@ int pc_readdb(void) continue; } job = pc->class2idx(job_id); - memcpy(exp_table[job][type], exp_table[jobs[0]][type], sizeof(exp_table[0][0])); - max_level[job][type] = maxlv; -// ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job_id, max_level[job][type]); + 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]); } } fclose(fp); @@ -9687,29 +10214,28 @@ int pc_readdb(void) if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER) continue; //Classes that do not need exp tables. j = pc->class2idx(i); - if (!max_level[j][0]) + if (!pc->max_level[j][0]) ShowWarning("Class %s (%d) does not has a base exp table.\n", pc->job_name(i), i); - if (!max_level[j][1]) + if (!pc->max_level[j][1]) ShowWarning("Class %s (%d) does not has a job exp table.\n", pc->job_name(i), i); } - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"exp.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"exp.txt"); count = 0; // Reset and read skilltree - memset(skill_tree,0,sizeof(skill_tree)); - sv->readdb(iMap->db_path, DBPATH"skill_tree.txt", ',', 3+MAX_PC_SKILL_REQUIRE*2, 4+MAX_PC_SKILL_REQUIRE*2, -1, &pc_readdb_skilltree); - + memset(pc->skill_tree,0,sizeof(pc->skill_tree)); + pc->read_skill_tree(); #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) - sv->readdb(iMap->db_path, "re/level_penalty.txt", ',', 4, 4, -1, &pc_readdb_levelpenalty); + sv->readdb(map->db_path, "re/level_penalty.txt", ',', 4, 4, -1, pc->readdb_levelpenalty); for( k=1; k < 3; k++ ){ // fill in the blanks for( j = 0; j < RC_MAX; j++ ){ int tmp = 0; for( i = 0; i < MAX_LEVEL*2; i++ ){ if( i == MAX_LEVEL+1 ) - tmp = level_penalty[k][j][0];// reset - if( level_penalty[k][j][i] > 0 ) - tmp = level_penalty[k][j][i]; + tmp = pc->level_penalty[k][j][0];// reset + if( pc->level_penalty[k][j][i] > 0 ) + tmp = pc->level_penalty[k][j][i]; else - level_penalty[k][j][i] = tmp; + pc->level_penalty[k][j][i] = tmp; } } } @@ -9719,9 +10245,9 @@ int pc_readdb(void) for(i=0;i<4;i++) for(j=0;j<ELE_MAX;j++) for(k=0;k<ELE_MAX;k++) - attr_fix_table[i][j][k]=100; + battle->attr_fix_table[i][j][k]=100; - sprintf(line, "%s/"DBPATH"attr_fix.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"attr_fix.txt", map->db_path); fp=fopen(line,"r"); if(fp==NULL){ @@ -9754,9 +10280,11 @@ int pc_readdb(void) for(j=0,p=line;j<n && j<ELE_MAX && p;j++){ while(*p==32 && *p>0) p++; - attr_fix_table[lv-1][i][j]=atoi(p); - if(battle_config.attr_recover == 0 && attr_fix_table[lv-1][i][j] < 0) - attr_fix_table[lv-1][i][j] = 0; + battle->attr_fix_table[lv-1][i][j]=atoi(p); +#ifndef RENEWAL + if(battle_config.attr_recover == 0 && battle->attr_fix_table[lv-1][i][j] < 0) + battle->attr_fix_table[lv-1][i][j] = 0; +#endif p=strchr(p,','); if(p) *p++=0; } @@ -9765,13 +10293,13 @@ int pc_readdb(void) } } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"attr_fix.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"attr_fix.txt"); count = 0; - // reset then read statspoint - memset(statp,0,sizeof(statp)); + // reset then read statspoint + memset(pc->statp,0,sizeof(pc->statp)); i=1; - sprintf(line, "%s/"DBPATH"statpoint.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"statpoint.txt", map->db_path); fp=fopen(line,"r"); if(fp == NULL){ ShowWarning("Can't read '"CL_WHITE"%s"CL_RESET"'... Generating DB.\n",line); @@ -9782,24 +10310,24 @@ int pc_readdb(void) int stat; if(line[0]=='/' && line[1]=='/') continue; - if ((stat=strtoul(line,NULL,10))<0) + if ((stat=(int)strtol(line,NULL,10))<0) stat=0; if (i > MAX_LEVEL) break; count++; - statp[i]=stat; + pc->statp[i]=stat; i++; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"statpoint.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"statpoint.txt"); } // generate the remaining parts of the db if necessary k = battle_config.use_statpoint_table; //save setting battle_config.use_statpoint_table = 0; //temporarily disable to force pc->gets_status_point use default values - statp[0] = 45; // seed value + pc->statp[0] = 45; // seed value for (; i <= MAX_LEVEL; i++) - statp[i] = statp[i-1] + pc->gets_status_point(i-1); + pc->statp[i] = pc->statp[i-1] + pc->gets_status_point(i-1); battle_config.use_statpoint_table = k; //restore setting return 0; @@ -9810,26 +10338,26 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { struct item_cd* cd = NULL; if( load ) { - if( !(cd = idb_get(itemcd_db, sd->status.char_id)) ) { + if( !(cd = idb_get(pc->itemcd_db, sd->status.char_id)) ) { // no skill cooldown is associated with this character return; } for(i = 0; i < MAX_ITEMDELAYS; i++) { - if( cd->nameid[i] && DIFF_TICK(iTimer->gettick(),cd->tick[i]) < 0 ) { + if( cd->nameid[i] && DIFF_TICK(timer->gettick(),cd->tick[i]) < 0 ) { sd->item_delay[cursor].tick = cd->tick[i]; sd->item_delay[cursor].nameid = cd->nameid[i]; cursor++; } } - idb_remove(itemcd_db,sd->status.char_id); + idb_remove(pc->itemcd_db,sd->status.char_id); } else { - if( !(cd = idb_get(itemcd_db,sd->status.char_id)) ) { + if( !(cd = idb_get(pc->itemcd_db,sd->status.char_id)) ) { // create a new skill cooldown object for map storage CREATE( cd, struct item_cd, 1 ); - idb_put( itemcd_db, sd->status.char_id, cd ); + idb_put( pc->itemcd_db, sd->status.char_id, cd ); } for(i = 0; i < MAX_ITEMDELAYS; i++) { - if( sd->item_delay[i].nameid && DIFF_TICK(iTimer->gettick(),sd->item_delay[i].tick) < 0 ) { + if( sd->item_delay[i].nameid && DIFF_TICK(timer->gettick(),sd->item_delay[i].tick) < 0 ) { cd->tick[cursor] = sd->item_delay[i].tick; cd->nameid[cursor] = sd->item_delay[i].nameid; cursor++; @@ -9839,79 +10367,456 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { return; } -/*========================================== - * pc Init/Terminate - *------------------------------------------*/ -void do_final_pc(void) { +void pc_bank_deposit(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.bank_vault; + + if( money <= 0 || limit_check > MAX_BANK_ZENY ) { + clif->bank_deposit(sd,BDA_OVERFLOW); + return; + } else if ( money > sd->status.zeny ) { + clif->bank_deposit(sd,BDA_NO_MONEY); + return; + } - db_destroy(itemcd_db); + if( pc->payzeny(sd,money, LOG_TYPE_BANK, NULL) ) + clif->bank_deposit(sd,BDA_NO_MONEY); + else { + sd->status.bank_vault += money; + if( map->save_settings&256 ) + chrif->save(sd,0); + clif->bank_deposit(sd,BDA_SUCCESS); + } +} +void pc_bank_withdraw(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.zeny; + + if( money <= 0 ) { + clif->bank_withdraw(sd,BWA_UNKNOWN_ERROR); + return; + } else if ( money > sd->status.bank_vault ) { + clif->bank_withdraw(sd,BWA_NO_MONEY); + return; + } else if ( limit_check > MAX_ZENY ) { + /* no official response for this scenario exists. */ + clif->colormes(sd->fd,COLOR_RED,msg_txt(1482)); + return; + } + + if( pc->getzeny(sd,money, LOG_TYPE_BANK, NULL) ) + clif->bank_withdraw(sd,BWA_NO_MONEY); + else { + sd->status.bank_vault -= money; + if( map->save_settings&256 ) + chrif->save(sd,0); + clif->bank_withdraw(sd,BWA_SUCCESS); + } +} +/* status change data arrived from char-server */ +void pc_scdata_received(struct map_session_data *sd) { + pc->inventory_rentals(sd); + clif->show_modifiers(sd); + + if (sd->expiration_time != 0) { // don't display if it's unlimited or unknow value + time_t exp_time = sd->expiration_time; + char tmpstr[1024]; + strftime(tmpstr, sizeof(tmpstr) - 1, msg_txt(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); + + pc->expire_check(sd); + } + + if( sd->state.standalone ) { + clif->pLoadEndAck(0,sd); + pc->autotrade_populate(sd); + pc->autotrade_start(sd); + } +} +int pc_expiration_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); + + if( !sd ) return 0; + + sd->expiration_tid = INVALID_TIMER; + + if( sd->fd ) + clif->authfail_fd(sd->fd,10); + + map->quit(sd); + + return 0; +} +/* this timer exists only when a character with a expire timer > 24h is online */ +/* it loops thru online players once an hour to check whether a new < 24h is available */ +int pc_global_expiration_timer(int tid, int64 tick, int id, intptr_t data) { + struct s_mapiterator* iter; + struct map_session_data* sd; - do_final_pc_groups(); + iter = mapit_getallusers(); - ers_destroy(pc_sc_display_ers); - return; + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if( sd->expiration_time ) + pc->expire_check(sd); + } + + mapit->free(iter); + + return 0; } +void pc_expire_check(struct map_session_data *sd) { + /* ongoing timer */ + if( sd->expiration_tid != INVALID_TIMER ) + return; + + /* not within the next 24h, enable the global check */ + if( sd->expiration_time > ( time(NULL) + ( ( 60 * 60 ) * 24 ) ) ) { + + /* global check not running, enable */ + if( pc->expiration_tid == INVALID_TIMER ) { + /* starts in 1h, repeats every hour */ + pc->expiration_tid = timer->add_interval(timer->gettick() + ((1000*60)*60), pc->global_expiration_timer, 0, 0, ((1000*60)*60)); + } + + return; + } -int do_init_pc(void) { + sd->expiration_tid = timer->add(timer->gettick() + (int64)(sd->expiration_time - time(NULL))*1000, pc->expiration_timer, sd->bl.id, 0); +} +/** + * Loads autotraders + ***/ +void pc_autotrade_load(void) { + struct map_session_data *sd; + char *data; + + if (SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `account_id`,`char_id`,`sex`,`title` FROM `%s`",map->autotrade_merchants_db)) + Sql_ShowDebug(map->mysql_handle); + + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { + int account_id, char_id; + char title[MESSAGE_SIZE]; + unsigned char sex; + + SQL->GetData(map->mysql_handle, 0, &data, NULL); account_id = atoi(data); + SQL->GetData(map->mysql_handle, 1, &data, NULL); char_id = atoi(data); + SQL->GetData(map->mysql_handle, 2, &data, NULL); sex = atoi(data); + SQL->GetData(map->mysql_handle, 3, &data, NULL); safestrncpy(title, data, sizeof(title)); - itemcd_db = idb_alloc(DB_OPT_RELEASE_DATA); + CREATE(sd, TBL_PC, 1); + + pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0); + + safestrncpy(sd->message, title, MESSAGE_SIZE); + + sd->state.standalone = 1; + sd->group = pcg->get_dummy_group(); + + chrif->authreq(sd,true); + } + + SQL->FreeResult(map->mysql_handle); +} +/** + * Loads vending data and sets it up, is triggered when char server data that pc_autotrade_load requested arrives + **/ +void pc_autotrade_start(struct map_session_data *sd) { + unsigned int count = 0; + int i; + char *data; - pc->readdb(); + 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); - iTimer->add_timer_func_list(pc_invincible_timer, "pc_invincible_timer"); - iTimer->add_timer_func_list(pc_eventtimer, "pc_eventtimer"); - iTimer->add_timer_func_list(pc_inventory_rental_end, "pc_inventory_rental_end"); - iTimer->add_timer_func_list(pc->calc_pvprank_timer, "pc->calc_pvprank_timer"); - iTimer->add_timer_func_list(pc_autosave, "pc_autosave"); - iTimer->add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); - iTimer->add_timer_func_list(pc_follow_timer, "pc_follow_timer"); - iTimer->add_timer_func_list(pc->endautobonus, "pc->endautobonus"); - iTimer->add_timer_func_list(pc_charm_timer, "pc_charm_timer"); + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { + int itemkey, amount, price; + + SQL->GetData(map->mysql_handle, 0, &data, NULL); itemkey = atoi(data); + SQL->GetData(map->mysql_handle, 1, &data, NULL); amount = atoi(data); + SQL->GetData(map->mysql_handle, 2, &data, NULL); price = atoi(data); - iTimer->add_timer(iTimer->gettick() + iMap->autosave_interval, pc_autosave, 0, 0); + ARR_FIND(0, MAX_CART, i, sd->status.cart[i].id == itemkey); + + if( i != MAX_CART && itemdb_cantrade(&sd->status.cart[i], 0, 0) ) { + if( amount > sd->status.cart[i].amount ) + amount = sd->status.cart[i].amount; + + if( amount ) { + sd->vending[count].index = i; + sd->vending[count].amount = amount; + sd->vending[count].value = cap_value(price, 0, (unsigned int)battle_config.vending_max_value); - // 0=day, 1=night [Yor] - iMap->night_flag = battle_config.night_at_start ? 1 : 0; + count++; + } + } + } + + if( !count ) { + pc->autotrade_update(sd,PAUC_REMOVE); + map->quit(sd); + } else { + sd->state.autotrade = 1; + sd->vender_id = ++vending->next_id; + sd->vend_num = count; + sd->state.vending = true; + idb_put(vending->db, sd->status.char_id, sd); + if( map->list[sd->bl.m].users ) + clif->showvendingboard(&sd->bl,sd->message,0); + } +} +/** + * Perform a autotrade action + **/ +void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update_action action) { + int i; + + /* 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)) + Sql_ShowDebug(map->mysql_handle); + } + + switch( action ) { + case PAUC_REMOVE: + if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' LIMIT 1",map->autotrade_merchants_db,sd->status.char_id)) + Sql_ShowDebug(map->mysql_handle); + break; + case PAUC_START: { + char title[MESSAGE_SIZE*2+1]; + + SQL->EscapeStringLen(map->mysql_handle, title, sd->message, strnlen(sd->message, MESSAGE_SIZE)); + + if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`account_id`,`char_id`,`sex`,`title`) VALUES ('%d','%d','%d','%s')", + map->autotrade_merchants_db, + sd->status.account_id, + sd->status.char_id, + sd->status.sex, + title + )) + Sql_ShowDebug(map->mysql_handle); + } + /* yes we want it to fall */ + 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')", + map->autotrade_data_db, + sd->status.char_id, + sd->status.cart[sd->vending[i].index].id, + sd->vending[i].amount, + sd->vending[i].value + )) + Sql_ShowDebug(map->mysql_handle); + } + break; + } +} +/** + * Handles characters upon @autotrade usage + **/ +void pc_autotrade_prepare(struct map_session_data *sd) { + struct autotrade_vending *data; + int i, cursor = 0; + int account_id, char_id; + char title[MESSAGE_SIZE]; + unsigned char sex; + + CREATE(data, struct autotrade_vending, 1); + + memcpy(data->vending, sd->vending, sizeof(sd->vending)); + + for(i = 0; i < sd->vend_num; i++) { + if( sd->vending[i].amount ) { + memcpy(&data->list[cursor],&sd->status.cart[sd->vending[i].index],sizeof(struct item)); + cursor++; + } + } + + data->vend_num = (unsigned char)cursor; + + idb_put(pc->at_db, sd->status.char_id, data); + + account_id = sd->status.account_id; + char_id = sd->status.char_id; + sex = sd->status.sex; + safestrncpy(title, sd->message, sizeof(title)); + + sd->npc_id = 0; + sd->npc_shopid = 0; + if (sd->st) { + sd->st->state = END; + sd->st = NULL; + } + map->quit(sd); + chrif->auth_delete(account_id, char_id, ST_LOGOUT); + + CREATE(sd, TBL_PC, 1); + + pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0); + + safestrncpy(sd->message, title, MESSAGE_SIZE); + + sd->state.standalone = 1; + sd->group = pcg->get_dummy_group(); + + chrif->authreq(sd,true); +} +/** + * Prepares autotrade data from pc->at_db from a player that has already returned from char server + **/ +void pc_autotrade_populate(struct map_session_data *sd) { + struct autotrade_vending *data; + int i, j, k, cursor = 0; + + if( !(data = idb_get(pc->at_db,sd->status.char_id)) ) + return; + + for(i = 0; i < data->vend_num; i++) { + if( !data->vending[i].amount ) + continue; + + for(j = 0; j < MAX_CART; j++) { + if( !memcmp((char*)(&data->list[i]) + sizeof(data->list[0].id), (char*)(&sd->status.cart[j]) + sizeof(data->list[0].id), sizeof(struct item) - sizeof(data->list[0].id)) ) { + if( cursor ) { + ARR_FIND(0, cursor, k, sd->vending[k].index == j); + if( k != cursor ) + continue; + } + break; + } + } + + if( j != MAX_CART ) { + sd->vending[cursor].index = j; + sd->vending[cursor].amount = data->vending[i].amount; + sd->vending[cursor].value = data->vending[i].value; + + cursor++; + } + } + + sd->vend_num = cursor; + + pc->autotrade_update(sd,PAUC_START); + + idb_remove(pc->at_db, sd->status.char_id); +} +void do_final_pc(void) { + + db_destroy(pc->itemcd_db); + db_destroy(pc->at_db); + + pcg->final(); + + ers_destroy(pc->sc_display_ers); + ers_destroy(pc->num_reg_ers); + ers_destroy(pc->str_reg_ers); + return; +} + +void do_init_pc(bool minimal) { + if (minimal) + return; + + pc->itemcd_db = idb_alloc(DB_OPT_RELEASE_DATA); + pc->at_db = idb_alloc(DB_OPT_RELEASE_DATA); + + pc->readdb(); + + timer->add_func_list(pc->invincible_timer, "pc_invincible_timer"); + timer->add_func_list(pc->eventtimer, "pc_eventtimer"); + timer->add_func_list(pc->inventory_rental_end, "pc_inventory_rental_end"); + timer->add_func_list(pc->calc_pvprank_timer, "pc_calc_pvprank_timer"); + timer->add_func_list(pc->autosave, "pc_autosave"); + timer->add_func_list(pc->spiritball_timer, "pc_spiritball_timer"); + timer->add_func_list(pc->follow_timer, "pc_follow_timer"); + timer->add_func_list(pc->endautobonus, "pc_endautobonus"); + timer->add_func_list(pc->charm_timer, "pc_charm_timer"); + timer->add_func_list(pc->global_expiration_timer,"pc_global_expiration_timer"); + timer->add_func_list(pc->expiration_timer,"pc_expiration_timer"); + + timer->add(timer->gettick() + map->autosave_interval, pc->autosave, 0, 0); + + // 0=day, 1=night [Yor] + map->night_flag = battle_config.night_at_start ? 1 : 0; + if (battle_config.day_duration > 0 && battle_config.night_duration > 0) { int day_duration = battle_config.day_duration; int night_duration = battle_config.night_duration; // add night/day timer [Yor] - iTimer->add_timer_func_list(pc->map_day_timer, "pc->map_day_timer"); - iTimer->add_timer_func_list(pc->map_night_timer, "pc->map_night_timer"); - - pc->day_timer_tid = iTimer->add_timer_interval(iTimer->gettick() + (iMap->night_flag ? 0 : day_duration) + night_duration, pc->map_day_timer, 0, 0, day_duration + night_duration); - pc->night_timer_tid = iTimer->add_timer_interval(iTimer->gettick() + day_duration + (iMap->night_flag ? night_duration : 0), pc->map_night_timer, 0, 0, day_duration + night_duration); + timer->add_func_list(pc->map_day_timer, "pc_map_day_timer"); + timer->add_func_list(pc->map_night_timer, "pc_map_night_timer"); + + pc->day_timer_tid = timer->add_interval(timer->gettick() + (map->night_flag ? 0 : day_duration) + night_duration, pc->map_day_timer, 0, 0, day_duration + night_duration); + pc->night_timer_tid = timer->add_interval(timer->gettick() + day_duration + (map->night_flag ? night_duration : 0), pc->map_night_timer, 0, 0, day_duration + night_duration); } - - do_init_pc_groups(); - pc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:pc_sc_display_ers", ERS_OPT_NONE); + pcg->init(); + + pc->sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:sc_display_ers", ERS_OPT_FLEX_CHUNK); + pc->num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.c::num_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + pc->str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.c::str_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); - return 0; + ers_chunk_size(pc->sc_display_ers, 150); + ers_chunk_size(pc->num_reg_ers, 300); + ers_chunk_size(pc->str_reg_ers, 50); } - /*===================================== -* Default Functions : pc.h +* Default Functions : pc.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ void pc_defaults(void) { + const struct sg_data sg_info[MAX_PC_FEELHATE] = { + { SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun }, + { SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon }, + { SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star } + }; + unsigned int equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO, EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L }; + pc = &pc_s; /* vars */ - // timer for night.day - pc->day_timer_tid = day_timer_tid; - pc->night_timer_tid = night_timer_tid; - + pc->at_db = NULL; + pc->itemcd_db = NULL; + /* */ + pc->day_timer_tid = INVALID_TIMER; + pc->night_timer_tid = INVALID_TIMER; + /* respecting order */ + memset(pc->exp_table, 0, sizeof(pc->exp_table) + + sizeof(pc->max_level) + + sizeof(pc->statp) + + sizeof(pc->level_penalty) + + sizeof(pc->skill_tree) + + sizeof(pc->smith_fame_list) + + sizeof(pc->chemist_fame_list) + + sizeof(pc->taekwon_fame_list) + ); + /* */ + memcpy(pc->equip_pos, &equip_pos, sizeof(pc->equip_pos)); + /* */ + memcpy(pc->sg_info, sg_info, sizeof(pc->sg_info)); + /* */ + pc->sc_display_ers = NULL; + /* */ + pc->expiration_tid = INVALID_TIMER; + /* */ + pc->num_reg_ers = NULL; + pc->str_reg_ers = NULL; + /* */ + pc->reg_load = false; /* funcs */ - + pc->init = do_init_pc; + pc->final = do_final_pc; + + pc->get_dummy_sd = pc_get_dummy_sd; pc->class2idx = pc_class2idx; - pc->get_group_level = pc_get_group_level; - pc->can_give_items = pc_can_give_items; pc->can_use_command = pc_can_use_command; - + pc->set_group = pc_set_group; + pc->should_log_commands = pc_should_log_commands; + pc->setrestartvalue = pc_setrestartvalue; pc->makesavestatus = pc_makesavestatus; pc->respawn = pc_respawn; @@ -9998,6 +10903,7 @@ void pc_defaults(void) { pc->thisjobexp = pc_thisjobexp; pc->gets_status_point = pc_gets_status_point; pc->need_status_point = pc_need_status_point; + pc->maxparameterincrease = pc_maxparameterincrease; pc->statusup = pc_statusup; pc->statusup2 = pc_statusup2; pc->skillup = pc_skillup; @@ -10063,6 +10969,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 @@ -10079,8 +10987,6 @@ void pc_defaults(void) { pc->set_hate_mob = pc_set_hate_mob; pc->readdb = pc_readdb; - pc->do_init_pc = do_init_pc; - pc->do_final_pc = do_final_pc; pc->map_day_timer = map_day_timer; // by [yor] pc->map_night_timer = map_night_timer; // by [yor] // Rental System @@ -10103,7 +11009,56 @@ void pc_defaults(void) { pc->del_charm = pc_del_charm; pc->baselevelchanged = pc_baselevelchanged; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) pc->level_penalty_mod = pc_level_penalty_mod; -#endif + + pc->calc_skillpoint = pc_calc_skillpoint; + + pc->invincible_timer = pc_invincible_timer; + pc->spiritball_timer = pc_spiritball_timer; + pc->check_banding = pc_check_banding; + pc->inventory_rental_end = pc_inventory_rental_end; + pc->check_skilltree = pc_check_skilltree; + pc->bonus_autospell = pc_bonus_autospell; + pc->bonus_autospell_onskill = pc_bonus_autospell_onskill; + pc->bonus_addeff = pc_bonus_addeff; + pc->bonus_addeff_onskill = pc_bonus_addeff_onskill; + pc->bonus_item_drop = pc_bonus_item_drop; + pc->calcexp = pc_calcexp; + pc->respawn_timer = pc_respawn_timer; + pc->jobchange_killclone = jobchange_killclone; + pc->getstat = pc_getstat; + pc->setstat = pc_setstat; + pc->eventtimer = pc_eventtimer; + pc->daynight_timer_sub = pc_daynight_timer_sub; + pc->charm_timer = pc_charm_timer; + pc->readdb_levelpenalty = pc_readdb_levelpenalty; + pc->autosave = pc_autosave; + pc->follow_timer = pc_follow_timer; + pc->read_skill_tree = pc_read_skill_tree; + pc->isUseitem = pc_isUseitem; + pc->show_steal = pc_show_steal; + pc->checkcombo = pc_checkcombo; + pc->calcweapontype = pc_calcweapontype; + pc->removecombo = pc_removecombo; + + pc->bank_withdraw = pc_bank_withdraw; + pc->bank_deposit = pc_bank_deposit; + + pc->rental_expire = pc_rental_expire; + pc->scdata_received = pc_scdata_received; + + pc->bound_clear = pc_bound_clear; + + pc->expiration_timer = pc_expiration_timer; + pc->global_expiration_timer = pc_global_expiration_timer; + pc->expire_check = pc_expire_check; + + /** + * Autotrade persistency [Ind/Hercules <3] + **/ + pc->autotrade_load = pc_autotrade_load; + pc->autotrade_update = pc_autotrade_update; + pc->autotrade_start = pc_autotrade_start; + pc->autotrade_prepare = pc_autotrade_prepare; + pc->autotrade_populate = pc_autotrade_populate; } |