Spirit Charm Update

* Fixes #464
* Cleaned up and optimized the Spirit Charm system for Kagerou/Orobo.
* Updated effects to mimic official server.
This commit is contained in:
aleos89 2015-06-16 08:55:11 -04:00
parent ef347830a0
commit 9f3fa0d757
9 changed files with 221 additions and 228 deletions

View File

@ -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

View File

@ -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]

View File

@ -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 );

View File

@ -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,

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);