From 9f3fa0d7579e334567fd81be1f4b892f7dd6fbd3 Mon Sep 17 00:00:00 2001 From: aleos89 Date: Tue, 16 Jun 2015 08:55:11 -0400 Subject: [PATCH] Spirit Charm Update * Fixes #464 * Cleaned up and optimized the Spirit Charm system for Kagerou/Orobo. * Updated effects to mimic official server. --- src/map/battle.c | 161 ++++++++++++++++------------------------------- src/map/clif.c | 31 ++++----- src/map/clif.h | 2 +- src/map/map.h | 12 ++++ src/map/pc.c | 152 +++++++++++++++++++++++++++----------------- src/map/pc.h | 10 +-- src/map/skill.c | 70 +++++++++++---------- src/map/status.c | 5 +- src/map/unit.c | 6 +- 9 files changed, 221 insertions(+), 228 deletions(-) diff --git a/src/map/battle.c b/src/map/battle.c index 1cac4c6f82..6de9aea3c1 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -2638,7 +2638,6 @@ static int battle_get_weapon_element(struct Damage wd, struct block_list *src, s struct map_session_data *sd = BL_CAST(BL_PC, src); struct status_change *sc = status_get_sc(src); struct status_data *sstatus = status_get_status_data(src); - uint8 i; int element = skill_get_ele(skill_id, skill_lv); //Take weapon's element @@ -2649,16 +2648,11 @@ static int battle_get_weapon_element(struct Damage wd, struct block_list *src, s element = sstatus->lhw.ele; if(is_skill_using_arrow(src, skill_id) && sd && sd->bonus.arrow_ele && weapon_position == EQI_HAND_R) element = sd->bonus.arrow_ele; + if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm >= MAX_SPIRITCHARM) + element = sd->spiritcharm_type; // Summoning 10 spiritcharm will endow your weapon // on official endows override all other elements [helvetica] - if (sd) { //Summoning 10 talisman will endow your weapon. - ARR_FIND(1, 6, i, sd->talisman[i] >= 10); - if (i < 5) - element = i; - if (sc) { // check for endows - if(sc->data[SC_ENCHANTARMS]) - element = sc->data[SC_ENCHANTARMS]->val2; - } - } + if(sc && sc->data[SC_ENCHANTARMS]) // Check for endows + element = sc->data[SC_ENCHANTARMS]->val2; } else if( element == -2 ) //Use enchantment's element element = status_get_attack_sc_element(src,sc); else if( element == -3 ) //Use random element @@ -4286,17 +4280,12 @@ struct Damage battle_attack_sc_bonus(struct Damage wd, struct block_list *src, s #endif int inf3 = skill_get_inf3(skill_id); - if (sd) { - int type; - - // Kagerou/Oboro Earth Charm effect +15% wATK - ARR_FIND(1, 6, type, sd->talisman[type] > 0); - if (type == 2) { //KO Earth Charm effect +15% wATK - ATK_ADDRATE(wd.damage, wd.damage2, 15 * sd->talisman[type]); + // Kagerou/Oboro Earth Charm effect +15% wATK + if(sd && sd->spiritcharm_type == CHARM_TYPE_LAND && sd->spiritcharm > 0) { + ATK_ADDRATE(wd.damage, wd.damage2, 15 * sd->spiritcharm); #ifdef RENEWAL - ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, 15 * sd->talisman[type]); + ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, 15 * sd->spiritcharm); #endif - } } //The following are applied on top of current damage and are stackable. @@ -4453,7 +4442,6 @@ struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list #endif if (sd) { - int type; int i = sd->ignore_def_by_race[tstatus->race] + sd->ignore_def_by_race[RC_ALL]; if (i) { @@ -4462,11 +4450,11 @@ struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list def2 -= def2 * i / 100; } - //Kagerou/Oboro Earth Charm effect +5% eDEF - ARR_FIND(1, 6, type, sd->talisman[type] > 0); - if (type == 2) { - short j = 5 * sd->talisman[type]; - def1 = (def1 * (100 + j)) / 100; + //Kagerou/Oboro Earth Charm effect +10% eDEF + if(sd->spiritcharm_type == CHARM_TYPE_LAND && sd->spiritcharm > 0) { + short i = 10 * sd->spiritcharm; + + def1 = (def1 * (100 + i)) / 100; } } @@ -5480,10 +5468,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (s_ele == -1){ // pl=-1 : the skill takes the weapon's element s_ele = sstatus->rhw.ele; - if( sd ){ //Summoning 10 talisman will endow your weapon - ARR_FIND(1, 6, i, sd->talisman[i] >= 10); - if( i < 5 ) s_ele = i; - } + if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm >= MAX_SPIRITCHARM) + s_ele = sd->spiritcharm_type; // Summoning 10 spiritcharm will endow your weapon }else if (s_ele == -2) //Use status element s_ele = status_get_attack_sc_element(src,status_get_sc(src)); else if( s_ele == -3 ) //Use random element @@ -5503,11 +5489,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list } break; case KO_KAIHOU: - if(sd) { - ARR_FIND(1, 6, i, sd->talisman[i] > 0); - if(i < 5) - s_ele = i; - } + if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) + s_ele = sd->spiritcharm_type; break; } @@ -5698,22 +5681,50 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list break; case NJ_KOUENKA: skillratio -= 10; + if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0) + skillratio += 20 * sd->spiritcharm; break; case NJ_KAENSIN: skillratio -= 50; + if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0) + skillratio += 10 * sd->spiritcharm; break; case NJ_BAKUENRYU: - skillratio += 50*(skill_lv-1); + skillratio += 50 * (skill_lv - 1); + if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0) + skillratio += 15 * sd->spiritcharm; + break; + case NJ_HYOUSENSOU: +#ifdef RENEWAL + skillratio -= 30; +#endif + if(sd && sd->spiritcharm_type == CHARM_TYPE_WATER && sd->spiritcharm > 0) + skillratio += 5 * sd->spiritcharm; break; case NJ_HYOUSYOURAKU: - skillratio += 50*skill_lv; + skillratio += 50 * skill_lv; + if(sd && sd->spiritcharm_type == CHARM_TYPE_WATER && sd->spiritcharm > 0) + skillratio += 25 * sd->spiritcharm; break; case NJ_RAIGEKISAI: - skillratio += 60 + 40*skill_lv; + skillratio += 60 + 40 * skill_lv; + if(sd && sd->spiritcharm_type == CHARM_TYPE_WIND && sd->spiritcharm > 0) + skillratio += 15 * sd->spiritcharm; break; case NJ_KAMAITACHI: + skillratio += 100 * skill_lv; + if(sd && sd->spiritcharm_type == CHARM_TYPE_WIND && sd->spiritcharm > 0) + skillratio += 10 * sd->spiritcharm; + break; + case NJ_HUUJIN: +#ifdef RENEWAL + skillratio += 50; +#endif + if(sd && sd->spiritcharm_type == CHARM_TYPE_WIND && sd->spiritcharm > 0) + skillratio += 20 * sd->spiritcharm; + break; case NPC_ENERGYDRAIN: - skillratio += 100*skill_lv; + skillratio += 100 * skill_lv; break; case NPC_EARTHQUAKE: skillratio += 100 +100*skill_lv +100*(skill_lv/2); @@ -5735,9 +5746,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list skillratio += ratio; } break; - case NJ_HUUJIN: - skillratio += 50; - break; #else case WZ_VERMILION: skillratio += 20*skill_lv-20; @@ -5921,18 +5929,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list skillratio += 10 + 20 * skill_lv; break; case KO_KAIHOU: - if(sd) { - int ttype; - - ARR_FIND(1, 6, ttype, sd->talisman[ttype] > 0); - if(ttype < 5) { - skillratio += -100 + 200 * sd->talisman[ttype]; - RE_LVL_DMOD(100); - pc_del_talisman(sd, sd->talisman[ttype], ttype); - } + if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) { + skillratio += -100 + 200 * sd->spiritcharm; + RE_LVL_DMOD(100); + pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type); } break; - // Magical Elemental Spirits Attack Skills + // Magical Elemental Spirits Attack Skills case EL_FIRE_MANTLE: case EL_WATER_SCREW: skillratio += 900; @@ -5968,62 +5971,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list break; } - if (sd) { - int sd_charm; - - ARR_FIND(1, 6, sd_charm, sd->talisman[sd_charm] > 0); - if(sd_charm < 5 && s_ele == sd_charm) { - switch(skill_id) { - case NJ_HYOUSYOURAKU: - skillratio += 25 * sd->talisman[sd_charm]; - break; - case NJ_KOUENKA: - case NJ_HUUJIN: - skillratio += 20 * sd->talisman[sd_charm]; - break; - case NJ_BAKUENRYU: - case NJ_RAIGEKISAI: - skillratio += 15 * sd->talisman[sd_charm]; - break; - case NJ_KAMAITACHI: - skillratio += 10 * sd->talisman[sd_charm]; - break; - case NJ_KAENSIN: - case NJ_HYOUSENSOU: - skillratio += 5 * sd->talisman[sd_charm]; - break; - } - } - } - - if (tsd) { - int tsd_charm; - - ARR_FIND(1, 6, tsd_charm, tsd->talisman[tsd_charm] > 0); - if(tsd_charm < 5 && s_ele == tsd_charm) { - switch(skill_id) { - case NJ_HYOUSYOURAKU: - skillratio -= 25 * tsd->talisman[tsd_charm]; - break; - case NJ_KOUENKA: - case NJ_HUUJIN: - skillratio -= 20 * tsd->talisman[tsd_charm]; - break; - case NJ_BAKUENRYU: - case NJ_RAIGEKISAI: - skillratio -= 15 * tsd->talisman[tsd_charm]; - break; - case NJ_KAMAITACHI: - skillratio -= 10 * tsd->talisman[tsd_charm]; - break; - case NJ_KAENSIN: - case NJ_HYOUSENSOU: - skillratio -= 5 * tsd->talisman[tsd_charm]; - break; - } - } - } - MATK_RATE(skillratio); //Constant/misc additions from skills diff --git a/src/map/clif.c b/src/map/clif.c index adc5eae4be..cfa13e40d2 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1250,13 +1250,13 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd) /*========================================== * Kagerou/Oboro amulet spirit *------------------------------------------*/ -static void clif_talisman_single(int fd, struct map_session_data *sd, short type) +static void clif_spiritcharm_single(int fd, struct map_session_data *sd) { WFIFOHEAD(fd, packet_len(0x08cf)); WFIFOW(fd,0)=0x08cf; WFIFOL(fd,2)=sd->bl.id; - WFIFOW(fd,6)=type; - WFIFOW(fd,8)=sd->talisman[type]; + WFIFOW(fd,6)=sd->spiritcharm_type; + WFIFOW(fd,8)=sd->spiritcharm; WFIFOSET(fd, packet_len(0x08cf)); } @@ -1354,10 +1354,8 @@ int clif_spawn(struct block_list *bl) clif_specialeffect(bl,421,AREA); if( sd->bg_id && map[sd->bl.m].flag.battleground ) clif_sendbgemblem_area(sd); - for(i = 1; i < 5; i++){ - if( sd->talisman[i] > 0 ) - clif_talisman(sd, i); - } + if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) + clif_spiritcharm(sd); for (i = 0; i < sd->sc_display_count; i++) { if (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK))) clif_status_change2(&sd->bl,sd->bl.id,AREA,SI_BLANK,0,0,0); @@ -4310,10 +4308,8 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d if(dstsd->spiritball > 0) clif_spiritball_single(sd->fd, dstsd); - for(i = 1; i < 5; i++){ - if( dstsd->talisman[i] > 0 ) - clif_talisman_single(sd->fd, dstsd, i); - } + if (dstsd->spiritcharm_type != CHARM_TYPE_NONE && dstsd->spiritcharm > 0) + clif_spiritcharm_single(sd->fd, dstsd); for( i = 0; i < dstsd->sc_display_count; i++ ) { if (dstsd->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK)) clif_status_change2(&sd->bl, dstsd->bl.id, SELF, SI_BLANK, 0, 0, 0); @@ -8870,7 +8866,6 @@ void clif_refresh_storagewindow(struct map_session_data *sd) { // refresh the client's screen, getting rid of any effects void clif_refresh(struct map_session_data *sd) { - int i; nullpo_retv(sd); clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y); @@ -8889,10 +8884,8 @@ void clif_refresh(struct map_session_data *sd) clif_updatestatus(sd,SP_LUK); if (sd->spiritball) clif_spiritball_single(sd->fd, sd); - for(i = 1; i < 5; i++){ - if( sd->talisman[i] > 0 ) - clif_talisman_single(sd->fd, sd, i); - } + if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) + clif_spiritcharm_single(sd->fd, sd); if (sd->vd.cloth_color) clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); if(hom_is_active(sd->hd)) @@ -17166,7 +17159,7 @@ void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd) { /*========================================== * Kagerou/Oboro amulet spirit *------------------------------------------*/ -void clif_talisman(struct map_session_data *sd,short type) +void clif_spiritcharm(struct map_session_data *sd) { unsigned char buf[10]; @@ -17174,8 +17167,8 @@ void clif_talisman(struct map_session_data *sd,short type) WBUFW(buf,0)=0x08cf; WBUFL(buf,2)=sd->bl.id; - WBUFW(buf,6)=type; - WBUFW(buf,8)=sd->talisman[type]; + WBUFW(buf,6)=sd->spiritcharm_type; + WBUFW(buf,8)=sd->spiritcharm; clif_send(buf,packet_len(0x08cf),&sd->bl,AREA); } /// Move Item from or to Personal Tab (CZ_WHATSOEVER) [FE] diff --git a/src/map/clif.h b/src/map/clif.h index 2b0a0ef6bb..db9b91388e 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -883,7 +883,7 @@ int clif_skill_itemlistwindow( struct map_session_data *sd, uint16 skill_id, uin void clif_elemental_info(struct map_session_data *sd); void clif_elemental_updatestatus(struct map_session_data *sd, int type); -void clif_talisman(struct map_session_data *sd, short type); +void clif_spiritcharm(struct map_session_data *sd); void clif_snap( struct block_list *bl, short x, short y ); void clif_monster_hp_bar( struct mob_data* md, int fd ); diff --git a/src/map/map.h b/src/map/map.h index 04169f59f4..82dacf1080 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -370,6 +370,18 @@ enum e_element { #define MAX_ELE_LEVEL 4 /// Maximum Element level +/** + * Types of spirit charms + * NOTE: Code assumes that this matches the first entries in enum elements + */ +enum spirit_charm_types { + CHARM_TYPE_NONE = 0, + CHARM_TYPE_WATER, + CHARM_TYPE_LAND, + CHARM_TYPE_FIRE, + CHARM_TYPE_WIND +}; + enum mob_ai { AI_NONE = 0, AI_ATTACK, diff --git a/src/map/pc.c b/src/map/pc.c index 1cecf81e78..c91b442bce 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -7345,8 +7345,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) if ( sd->spiritball !=0 ) pc_delspiritball(sd,sd->spiritball,0); - for(i = 1; i < 5; i++) - pc_del_talisman(sd, sd->talisman[i], i); + if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) + pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type); if (src) switch (src->type) { @@ -10207,102 +10207,138 @@ bool pc_should_log_commands(struct map_session_data *sd) return pc_group_should_log_commands(pc_get_group_id(sd)); } -static int pc_talisman_timer(int tid, unsigned int tick, int id, intptr_t data) +/** + * Spirit Charm expiration timer. + * @see TimerFunc + */ +static int pc_spiritcharm_timer(int tid, unsigned int tick, int id, intptr_t data) { struct map_session_data *sd; - int i, type; + int i; - if( (sd=(struct map_session_data *)map_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->talisman[type] > 0); - - if( sd->talisman[type] <= 0 ) - { - ShowError("pc_talisman_timer: %d talisman's available. (aid=%d cid=%d tid=%d)\n", sd->talisman[type], sd->status.account_id, sd->status.char_id, tid); - sd->talisman[type] = 0; + if (sd->spiritcharm <= 0) { + ShowError("pc_spiritcharm_timer: %d spiritcharm's available. (aid=%d cid=%d tid=%d)\n", sd->spiritcharm, sd->status.account_id, sd->status.char_id, tid); + sd->spiritcharm = 0; + sd->spiritcharm_type = CHARM_TYPE_NONE; return 0; } - ARR_FIND(0, sd->talisman[type], i, sd->talisman_timer[type][i] == tid); - if( i == sd->talisman[type] ) - { - ShowError("pc_talisman_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid); + ARR_FIND(0, sd->spiritcharm, i, sd->spiritcharm_timer[i] == tid); + + if (i == sd->spiritcharm) { + ShowError("pc_spiritcharm_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid); return 0; } - sd->talisman[type]--; - if( i != sd->talisman[type] ) - memmove(sd->talisman_timer[type]+i, sd->talisman_timer[type]+i+1, (sd->talisman[type]-i)*sizeof(int)); - sd->talisman_timer[type][sd->talisman[type]] = INVALID_TIMER; + sd->spiritcharm--; - clif_talisman(sd, type); + if (i != sd->spiritcharm) + memmove(sd->spiritcharm_timer + i, sd->spiritcharm_timer + i + 1, (sd->spiritcharm - i) * sizeof(int)); + + sd->spiritcharm_timer[sd->spiritcharm] = INVALID_TIMER; + + if (sd->spiritcharm <= 0) + sd->spiritcharm_type = CHARM_TYPE_NONE; + + clif_spiritcharm(sd); return 0; } -void pc_add_talisman(struct map_session_data *sd,int interval,int max,int type) +/** + * Adds a spirit charm. + * @param sd: Target character + * @param interval: Duration + * @param max: Maximum amount of charms to add + * @param type: Charm type (@see spirit_charm_types) + */ +void pc_addspiritcharm(struct map_session_data *sd, int interval, int max, int type) { int tid, i; nullpo_retv(sd); - if(max > 10) - max = 10; - if(sd->talisman[type] < 0) - sd->talisman[type] = 0; + if (sd->spiritcharm_type != CHARM_TYPE_NONE && type != sd->spiritcharm_type) + pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type); - if( sd->talisman[type] && sd->talisman[type] >= max ) - { - if(sd->talisman_timer[type][0] != INVALID_TIMER) - delete_timer(sd->talisman_timer[type][0],pc_talisman_timer); - sd->talisman[type]--; - if( sd->talisman[type] != 0 ) - memmove(sd->talisman_timer[type]+0, sd->talisman_timer[type]+1, (sd->talisman[type])*sizeof(int)); - sd->talisman_timer[type][sd->talisman[type]] = INVALID_TIMER; + if (max > MAX_SPIRITCHARM) + max = MAX_SPIRITCHARM; + + if (sd->spiritcharm < 0) + sd->spiritcharm = 0; + + if (sd->spiritcharm && sd->spiritcharm >= max) { + if (sd->spiritcharm_timer[0] != INVALID_TIMER) + delete_timer(sd->spiritcharm_timer[0], pc_spiritcharm_timer); + sd->spiritcharm--; + if (sd->spiritcharm != 0) + memmove(sd->spiritcharm_timer + 0, sd->spiritcharm_timer + 1, (sd->spiritcharm) * sizeof(int)); + sd->spiritcharm_timer[sd->spiritcharm] = INVALID_TIMER; } - tid = add_timer(gettick()+interval, pc_talisman_timer, sd->bl.id, 0); - ARR_FIND(0, sd->talisman[type], i, sd->talisman_timer[type][i] == INVALID_TIMER || DIFF_TICK(get_timer(tid)->tick, get_timer(sd->talisman_timer[type][i])->tick) < 0); - if( i != sd->talisman[type] ) - memmove(sd->talisman_timer[type]+i+1, sd->talisman_timer[type]+i, (sd->talisman[type]-i)*sizeof(int)); - sd->talisman_timer[type][i] = tid; - sd->talisman[type]++; + tid = add_timer(gettick() + interval, pc_spiritcharm_timer, sd->bl.id, 0); + ARR_FIND(0, sd->spiritcharm, i, sd->spiritcharm_timer[i] == INVALID_TIMER || DIFF_TICK(get_timer(tid)->tick, get_timer(sd->spiritcharm_timer[i])->tick) < 0); - clif_talisman(sd, type); + if (i != sd->spiritcharm) + memmove(sd->spiritcharm_timer + i + 1, sd->spiritcharm_timer + i, (sd->spiritcharm - i) * sizeof(int)); + + sd->spiritcharm_timer[i] = tid; + sd->spiritcharm++; + sd->spiritcharm_type = type; + + clif_spiritcharm(sd); } -void pc_del_talisman(struct map_session_data *sd,int count,int type) +/** + * Removes one or more spirit charms. + * @param sd: The target character + * @param count: Amount of charms to remove + * @param type: Type of charm to remove + */ +void pc_delspiritcharm(struct map_session_data *sd, int count, int type) { int i; nullpo_retv(sd); - if( sd->talisman[type] <= 0 ) { - sd->talisman[type] = 0; + if (sd->spiritcharm_type != type) + return; + + if (sd->spiritcharm <= 0) { + sd->spiritcharm = 0; return; } - if( count <= 0 ) + if (count <= 0) return; - if( count > sd->talisman[type] ) - count = sd->talisman[type]; - sd->talisman[type] -= count; - if( count > 10 ) - count = 10; - for(i = 0; i < count; i++) { - if(sd->talisman_timer[type][i] != INVALID_TIMER) { - delete_timer(sd->talisman_timer[type][i],pc_talisman_timer); - sd->talisman_timer[type][i] = INVALID_TIMER; + if (count > sd->spiritcharm) + count = sd->spiritcharm; + + sd->spiritcharm -= count; + + if (count > MAX_SPIRITCHARM) + count = MAX_SPIRITCHARM; + + for (i = 0; i < count; i++) { + if (sd->spiritcharm_timer[i] != INVALID_TIMER) { + delete_timer(sd->spiritcharm_timer[i], pc_spiritcharm_timer); + sd->spiritcharm_timer[i] = INVALID_TIMER; } } - for(i = count; i < 10; i++) { - sd->talisman_timer[type][i-count] = sd->talisman_timer[type][i]; - sd->talisman_timer[type][i] = INVALID_TIMER; + + for (i = count; i < MAX_SPIRITCHARM; i++) { + sd->spiritcharm_timer[i - count] = sd->spiritcharm_timer[i]; + sd->spiritcharm_timer[i] = INVALID_TIMER; } - clif_talisman(sd, type); + if (sd->spiritcharm <= 0) + sd->spiritcharm_type = CHARM_TYPE_NONE; + + clif_spiritcharm(sd); } #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) @@ -11629,7 +11665,7 @@ void do_init_pc(void) { add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); add_timer_func_list(pc_follow_timer, "pc_follow_timer"); add_timer_func_list(pc_endautobonus, "pc_endautobonus"); - add_timer_func_list(pc_talisman_timer, "pc_talisman_timer"); + add_timer_func_list(pc_spiritcharm_timer, "pc_spiritcharm_timer"); add_timer_func_list(pc_global_expiration_timer, "pc_global_expiration_timer"); add_timer_func_list(pc_expiration_timer, "pc_expiration_timer"); add_timer_func_list(pc_autotrade_timer, "pc_autotrade_timer"); diff --git a/src/map/pc.h b/src/map/pc.h index 09fdafbacd..1e372dab4f 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -28,6 +28,7 @@ #define DAMAGELOG_SIZE_PC 100 /// Damage log #define MAX_SPIRITBALL 15 /// Max spirit balls #define MAX_DEVOTION 5 /// Max Devotion slots +#define MAX_SPIRITCHARM 10 /// Max spirit charms #define BANK_VAULT_VAR "#BANKVAULT" @@ -456,8 +457,9 @@ struct map_session_data { int8 spiritball, spiritball_old; int spirit_timer[MAX_SPIRITBALL]; - short talisman[ELE_POISON+1]; // There are actually 5 talisman Fire, Ice, Wind, Earth & Poison maybe because its color violet. - int talisman_timer[ELE_POISON+1][10]; + short spiritcharm; //No. of spirit + int spiritcharm_type; //Spirit type + int spiritcharm_timer[MAX_SPIRITCHARM]; unsigned char potion_success_counter; //Potion successes in row counter unsigned char mission_count; //Stores the bounty kill count for TK_MISSION @@ -1144,8 +1146,8 @@ void pc_itemcd_do(struct map_session_data *sd, bool load); int pc_load_combo(struct map_session_data *sd); -void pc_add_talisman(struct map_session_data *sd,int interval,int max,int type); -void pc_del_talisman(struct map_session_data *sd,int count,int type); +void pc_addspiritcharm(struct map_session_data *sd, int interval, int max, int type); +void pc_delspiritcharm(struct map_session_data *sd, int count, int type); void pc_baselevelchanged(struct map_session_data *sd); diff --git a/src/map/skill.c b/src/map/skill.c index 79af5cdd5d..943b49882e 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -6491,8 +6491,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui i = 0; if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m) || (sd && sd->duel_group && sd->duel_group == dstsd->duel_group)) && ((dstsd->class_&MAPID_BASEMASK) != MAPID_GUNSLINGER || (dstsd->class_&MAPID_UPPERMASK) != MAPID_REBELLION)) { // split the if for readability, and included gunslingers in the check so that their coins cannot be removed [Reddozen] - i = dstsd->spiritball * 7; - pc_delspiritball(dstsd,dstsd->spiritball,0); + if (dstsd->spiritball > 0) { + i = dstsd->spiritball * 7; + pc_delspiritball(dstsd,dstsd->spiritball,0); + } + if (dstsd->spiritcharm_type != CHARM_TYPE_NONE && dstsd->spiritcharm > 0) { + i += dstsd->spiritcharm * 7; + pc_delspiritcharm(dstsd,dstsd->spiritcharm,dstsd->spiritcharm_type); + } } else if (dstmd && !(tstatus->mode&MD_BOSS) && rnd() % 100 < 20) { // check if target is a monster and not a Boss, for the 20% chance to absorb 2 SP per monster's level [Reddozen] i = 2 * dstmd->level; mob_target(dstmd,src,0); @@ -9445,14 +9451,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case SR_ASSIMILATEPOWER: - if( flag&1 ) { + if (flag&1) { i = 0; - if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) - { - i = dstsd->spiritball; //1%sp per spiritball. - pc_delspiritball(dstsd, dstsd->spiritball, 0); + if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) { + if (dstsd->spiritball > 0) { + i = dstsd->spiritball; + pc_delspiritball(dstsd,dstsd->spiritball,0); + } + if (dstsd->spiritcharm_type != CHARM_TYPE_NONE && dstsd->spiritcharm > 0) { + i += dstsd->spiritcharm; + pc_delspiritcharm(dstsd,dstsd->spiritcharm,dstsd->spiritcharm_type); + } } - if( i ) status_percent_heal(src, 0, i); + if (i) + status_percent_heal(src, 0, i); clif_skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0); } else { clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); @@ -10037,13 +10049,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KO_HYOUHU_HUBUKI: case KO_KAZEHU_SEIRAN: case KO_DOHU_KOUKAI: - if(sd) { - int i_tal, ttype = skill_get_ele(skill_id, skill_lv); - clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); - ARR_FIND(1, 6, i_tal, sd->talisman[i_tal] > 0 && ttype != i_tal); - if( i_tal < 6 ) - pc_del_talisman(sd, sd->talisman[i_tal], i_tal); // Replace talisman - pc_add_talisman(sd, skill_get_time(skill_id, skill_lv), 10, ttype); + if (sd) { + int type = skill_get_ele(skill_id,skill_lv); + + clif_skill_nodamage(src,bl,skill_id,skill_lv,1); + pc_addspiritcharm(sd,skill_get_time(skill_id,skill_lv),MAX_SPIRITCHARM,type); } break; case KO_ZANZOU: @@ -12322,15 +12332,12 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_ limit = ((sd ? pc_checkskill(sd,GN_DEMONIC_FIRE) : 1) + 1) * limit; break; case KO_ZENKAI: - if( sd ){ - ARR_FIND(1, 6, i, sd->talisman[i] > 0); - if( i < 5 ){ - val1 = sd->talisman[i]; // no. of aura - val2 = i; // aura type - limit += val1 * 1000; - subunt = i - 1; - pc_del_talisman(sd, sd->talisman[i], i); - } + if (sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) { + val1 = sd->spiritcharm; + val2 = sd->spiritcharm_type; + limit = 6000 * val1; + subunt = sd->spiritcharm_type - 1; + pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type); } break; case HW_GRAVITATION: @@ -14779,20 +14786,15 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i case KO_HYOUHU_HUBUKI: case KO_KAZEHU_SEIRAN: case KO_DOHU_KOUKAI: - { - int ttype = skill_get_ele(skill_id, skill_lv); - ARR_FIND(1, 5, i, sd->talisman[i] > 0 && i != ttype); - if( sd->talisman[ttype] >= 10 ) { - clif_skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0); - return false; - } + if (sd->spiritcharm_type == skill_get_ele(skill_id,skill_lv) && sd->spiritcharm >= MAX_SPIRITCHARM) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); + return false; } break; case KO_KAIHOU: case KO_ZENKAI: - ARR_FIND(1, 6, i, sd->talisman[i] > 0); - if( i > 4 ) { - clif_skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0); + if (sd->spiritcharm_type == CHARM_TYPE_NONE || sd->spiritcharm <= 0) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0); return false; } break; diff --git a/src/map/status.c b/src/map/status.c index 93ee641225..57b7e7defe 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -9614,7 +9614,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC__ENERVATION: val2 = 20 + 10 * val1; // ATK Reduction - if( sd ) pc_delspiritball(sd,sd->spiritball,0); + if (sd) { + pc_delspiritball(sd,sd->spiritball,0); + pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type); + } break; case SC__GROOMY: val2 = 20 + 10 * val1; // ASPD diff --git a/src/map/unit.c b/src/map/unit.c index 7f95f9fdce..3140df8765 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -3163,10 +3163,8 @@ int unit_free(struct block_list *bl, clr_type clrtype) guild_send_memberinfoshort(sd,0); pc_cleareventtimer(sd); pc_inventory_rental_clear(sd); - pc_delspiritball(sd,sd->spiritball,1); - - for(i = 1; i < 5; i++) - pc_del_talisman(sd, sd->talisman[i], i); + pc_delspiritball(sd, sd->spiritball, 1); + pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type); if( sd->reg ) { // Double logout already freed pointer fix... [Skotlex] aFree(sd->reg);