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 map_session_data *sd = BL_CAST(BL_PC, src);
struct status_change *sc = status_get_sc(src); struct status_change *sc = status_get_sc(src);
struct status_data *sstatus = status_get_status_data(src); struct status_data *sstatus = status_get_status_data(src);
uint8 i;
int element = skill_get_ele(skill_id, skill_lv); int element = skill_get_ele(skill_id, skill_lv);
//Take weapon's element //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; element = sstatus->lhw.ele;
if(is_skill_using_arrow(src, skill_id) && sd && sd->bonus.arrow_ele && weapon_position == EQI_HAND_R) if(is_skill_using_arrow(src, skill_id) && sd && sd->bonus.arrow_ele && weapon_position == EQI_HAND_R)
element = sd->bonus.arrow_ele; 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] // on official endows override all other elements [helvetica]
if (sd) { //Summoning 10 talisman will endow your weapon. if(sc && sc->data[SC_ENCHANTARMS]) // Check for endows
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; element = sc->data[SC_ENCHANTARMS]->val2;
}
}
} else if( element == -2 ) //Use enchantment's element } else if( element == -2 ) //Use enchantment's element
element = status_get_attack_sc_element(src,sc); element = status_get_attack_sc_element(src,sc);
else if( element == -3 ) //Use random element else if( element == -3 ) //Use random element
@ -4286,18 +4280,13 @@ struct Damage battle_attack_sc_bonus(struct Damage wd, struct block_list *src, s
#endif #endif
int inf3 = skill_get_inf3(skill_id); int inf3 = skill_get_inf3(skill_id);
if (sd) {
int type;
// Kagerou/Oboro Earth Charm effect +15% wATK // Kagerou/Oboro Earth Charm effect +15% wATK
ARR_FIND(1, 6, type, sd->talisman[type] > 0); if(sd && sd->spiritcharm_type == CHARM_TYPE_LAND && sd->spiritcharm > 0) {
if (type == 2) { //KO Earth Charm effect +15% wATK ATK_ADDRATE(wd.damage, wd.damage2, 15 * sd->spiritcharm);
ATK_ADDRATE(wd.damage, wd.damage2, 15 * sd->talisman[type]);
#ifdef RENEWAL #ifdef RENEWAL
ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, 15 * sd->talisman[type]); ATK_ADDRATE(wd.weaponAtk, wd.weaponAtk2, 15 * sd->spiritcharm);
#endif #endif
} }
}
//The following are applied on top of current damage and are stackable. //The following are applied on top of current damage and are stackable.
if (sc) { if (sc) {
@ -4453,7 +4442,6 @@ struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list
#endif #endif
if (sd) { if (sd) {
int type;
int i = sd->ignore_def_by_race[tstatus->race] + sd->ignore_def_by_race[RC_ALL]; int i = sd->ignore_def_by_race[tstatus->race] + sd->ignore_def_by_race[RC_ALL];
if (i) { if (i) {
@ -4462,11 +4450,11 @@ struct Damage battle_calc_defense_reduction(struct Damage wd, struct block_list
def2 -= def2 * i / 100; def2 -= def2 * i / 100;
} }
//Kagerou/Oboro Earth Charm effect +5% eDEF //Kagerou/Oboro Earth Charm effect +10% eDEF
ARR_FIND(1, 6, type, sd->talisman[type] > 0); if(sd->spiritcharm_type == CHARM_TYPE_LAND && sd->spiritcharm > 0) {
if (type == 2) { short i = 10 * sd->spiritcharm;
short j = 5 * sd->talisman[type];
def1 = (def1 * (100 + j)) / 100; 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 if (s_ele == -1){ // pl=-1 : the skill takes the weapon's element
s_ele = sstatus->rhw.ele; s_ele = sstatus->rhw.ele;
if( sd ){ //Summoning 10 talisman will endow your weapon if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm >= MAX_SPIRITCHARM)
ARR_FIND(1, 6, i, sd->talisman[i] >= 10); s_ele = sd->spiritcharm_type; // Summoning 10 spiritcharm will endow your weapon
if( i < 5 ) s_ele = i;
}
}else if (s_ele == -2) //Use status element }else if (s_ele == -2) //Use status element
s_ele = status_get_attack_sc_element(src,status_get_sc(src)); s_ele = status_get_attack_sc_element(src,status_get_sc(src));
else if( s_ele == -3 ) //Use random element 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; break;
case KO_KAIHOU: case KO_KAIHOU:
if(sd) { if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0)
ARR_FIND(1, 6, i, sd->talisman[i] > 0); s_ele = sd->spiritcharm_type;
if(i < 5)
s_ele = i;
}
break; break;
} }
@ -5698,22 +5681,50 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
break; break;
case NJ_KOUENKA: case NJ_KOUENKA:
skillratio -= 10; skillratio -= 10;
if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0)
skillratio += 20 * sd->spiritcharm;
break; break;
case NJ_KAENSIN: case NJ_KAENSIN:
skillratio -= 50; skillratio -= 50;
if(sd && sd->spiritcharm_type == CHARM_TYPE_FIRE && sd->spiritcharm > 0)
skillratio += 10 * sd->spiritcharm;
break; break;
case NJ_BAKUENRYU: 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; break;
case NJ_HYOUSYOURAKU: 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; break;
case NJ_RAIGEKISAI: 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; break;
case NJ_KAMAITACHI: 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: case NPC_ENERGYDRAIN:
skillratio += 100*skill_lv; skillratio += 100 * skill_lv;
break; break;
case NPC_EARTHQUAKE: case NPC_EARTHQUAKE:
skillratio += 100 +100*skill_lv +100*(skill_lv/2); 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; skillratio += ratio;
} }
break; break;
case NJ_HUUJIN:
skillratio += 50;
break;
#else #else
case WZ_VERMILION: case WZ_VERMILION:
skillratio += 20*skill_lv-20; skillratio += 20*skill_lv-20;
@ -5921,15 +5929,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
skillratio += 10 + 20 * skill_lv; skillratio += 10 + 20 * skill_lv;
break; break;
case KO_KAIHOU: case KO_KAIHOU:
if(sd) { if(sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) {
int ttype; skillratio += -100 + 200 * sd->spiritcharm;
ARR_FIND(1, 6, ttype, sd->talisman[ttype] > 0);
if(ttype < 5) {
skillratio += -100 + 200 * sd->talisman[ttype];
RE_LVL_DMOD(100); RE_LVL_DMOD(100);
pc_del_talisman(sd, sd->talisman[ttype], ttype); pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type);
}
} }
break; break;
// Magical Elemental Spirits Attack Skills // Magical Elemental Spirits Attack Skills
@ -5968,62 +5971,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
break; 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); MATK_RATE(skillratio);
//Constant/misc additions from skills //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 * 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)); WFIFOHEAD(fd, packet_len(0x08cf));
WFIFOW(fd,0)=0x08cf; WFIFOW(fd,0)=0x08cf;
WFIFOL(fd,2)=sd->bl.id; WFIFOL(fd,2)=sd->bl.id;
WFIFOW(fd,6)=type; WFIFOW(fd,6)=sd->spiritcharm_type;
WFIFOW(fd,8)=sd->talisman[type]; WFIFOW(fd,8)=sd->spiritcharm;
WFIFOSET(fd, packet_len(0x08cf)); WFIFOSET(fd, packet_len(0x08cf));
} }
@ -1354,10 +1354,8 @@ int clif_spawn(struct block_list *bl)
clif_specialeffect(bl,421,AREA); clif_specialeffect(bl,421,AREA);
if( sd->bg_id && map[sd->bl.m].flag.battleground ) if( sd->bg_id && map[sd->bl.m].flag.battleground )
clif_sendbgemblem_area(sd); clif_sendbgemblem_area(sd);
for(i = 1; i < 5; i++){ if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0)
if( sd->talisman[i] > 0 ) clif_spiritcharm(sd);
clif_talisman(sd, i);
}
for (i = 0; i < sd->sc_display_count; i++) { for (i = 0; i < sd->sc_display_count; i++) {
if (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK))) 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); 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) if(dstsd->spiritball > 0)
clif_spiritball_single(sd->fd, dstsd); clif_spiritball_single(sd->fd, dstsd);
for(i = 1; i < 5; i++){ if (dstsd->spiritcharm_type != CHARM_TYPE_NONE && dstsd->spiritcharm > 0)
if( dstsd->talisman[i] > 0 ) clif_spiritcharm_single(sd->fd, dstsd);
clif_talisman_single(sd->fd, dstsd, i);
}
for( i = 0; i < dstsd->sc_display_count; i++ ) { for( i = 0; i < dstsd->sc_display_count; i++ ) {
if (dstsd->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK)) 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); 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 // refresh the client's screen, getting rid of any effects
void clif_refresh(struct map_session_data *sd) void clif_refresh(struct map_session_data *sd)
{ {
int i;
nullpo_retv(sd); nullpo_retv(sd);
clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y); 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); clif_updatestatus(sd,SP_LUK);
if (sd->spiritball) if (sd->spiritball)
clif_spiritball_single(sd->fd, sd); clif_spiritball_single(sd->fd, sd);
for(i = 1; i < 5; i++){ if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0)
if( sd->talisman[i] > 0 ) clif_spiritcharm_single(sd->fd, sd);
clif_talisman_single(sd->fd, sd, i);
}
if (sd->vd.cloth_color) if (sd->vd.cloth_color)
clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF);
if(hom_is_active(sd->hd)) 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 * 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]; unsigned char buf[10];
@ -17174,8 +17167,8 @@ void clif_talisman(struct map_session_data *sd,short type)
WBUFW(buf,0)=0x08cf; WBUFW(buf,0)=0x08cf;
WBUFL(buf,2)=sd->bl.id; WBUFL(buf,2)=sd->bl.id;
WBUFW(buf,6)=type; WBUFW(buf,6)=sd->spiritcharm_type;
WBUFW(buf,8)=sd->talisman[type]; WBUFW(buf,8)=sd->spiritcharm;
clif_send(buf,packet_len(0x08cf),&sd->bl,AREA); clif_send(buf,packet_len(0x08cf),&sd->bl,AREA);
} }
/// Move Item from or to Personal Tab (CZ_WHATSOEVER) [FE] /// 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_info(struct map_session_data *sd);
void clif_elemental_updatestatus(struct map_session_data *sd, int type); 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_snap( struct block_list *bl, short x, short y );
void clif_monster_hp_bar( struct mob_data* md, int fd ); 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 #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 { enum mob_ai {
AI_NONE = 0, AI_NONE = 0,
AI_ATTACK, AI_ATTACK,

View File

@ -7345,8 +7345,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
if ( sd->spiritball !=0 ) if ( sd->spiritball !=0 )
pc_delspiritball(sd,sd->spiritball,0); pc_delspiritball(sd,sd->spiritball,0);
for(i = 1; i < 5; i++) if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0)
pc_del_talisman(sd, sd->talisman[i], i); pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type);
if (src) if (src)
switch (src->type) { 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)); 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; 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; return 1;
ARR_FIND(1, 5, type, 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);
if( sd->talisman[type] <= 0 ) sd->spiritcharm = 0;
{ sd->spiritcharm_type = CHARM_TYPE_NONE;
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;
return 0; return 0;
} }
ARR_FIND(0, sd->talisman[type], i, sd->talisman_timer[type][i] == tid); ARR_FIND(0, sd->spiritcharm, i, sd->spiritcharm_timer[i] == tid);
if( i == sd->talisman[type] )
{ if (i == sd->spiritcharm) {
ShowError("pc_talisman_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid); 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; return 0;
} }
sd->talisman[type]--; sd->spiritcharm--;
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;
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; 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; int tid, i;
nullpo_retv(sd); nullpo_retv(sd);
if(max > 10) if (sd->spiritcharm_type != CHARM_TYPE_NONE && type != sd->spiritcharm_type)
max = 10; pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type);
if(sd->talisman[type] < 0)
sd->talisman[type] = 0;
if( sd->talisman[type] && sd->talisman[type] >= max ) if (max > MAX_SPIRITCHARM)
{ max = MAX_SPIRITCHARM;
if(sd->talisman_timer[type][0] != INVALID_TIMER)
delete_timer(sd->talisman_timer[type][0],pc_talisman_timer); if (sd->spiritcharm < 0)
sd->talisman[type]--; sd->spiritcharm = 0;
if( sd->talisman[type] != 0 )
memmove(sd->talisman_timer[type]+0, sd->talisman_timer[type]+1, (sd->talisman[type])*sizeof(int)); if (sd->spiritcharm && sd->spiritcharm >= max) {
sd->talisman_timer[type][sd->talisman[type]] = INVALID_TIMER; 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); tid = add_timer(gettick() + interval, pc_spiritcharm_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); 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);
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]++;
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; int i;
nullpo_retv(sd); nullpo_retv(sd);
if( sd->talisman[type] <= 0 ) { if (sd->spiritcharm_type != type)
sd->talisman[type] = 0; return;
if (sd->spiritcharm <= 0) {
sd->spiritcharm = 0;
return; return;
} }
if( count <= 0 ) if (count <= 0)
return; 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 (count > sd->spiritcharm)
if(sd->talisman_timer[type][i] != INVALID_TIMER) { count = sd->spiritcharm;
delete_timer(sd->talisman_timer[type][i],pc_talisman_timer);
sd->talisman_timer[type][i] = INVALID_TIMER; 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;
}
clif_talisman(sd, type); for (i = count; i < MAX_SPIRITCHARM; i++) {
sd->spiritcharm_timer[i - count] = sd->spiritcharm_timer[i];
sd->spiritcharm_timer[i] = INVALID_TIMER;
}
if (sd->spiritcharm <= 0)
sd->spiritcharm_type = CHARM_TYPE_NONE;
clif_spiritcharm(sd);
} }
#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) #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_spiritball_timer, "pc_spiritball_timer");
add_timer_func_list(pc_follow_timer, "pc_follow_timer"); add_timer_func_list(pc_follow_timer, "pc_follow_timer");
add_timer_func_list(pc_endautobonus, "pc_endautobonus"); 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_global_expiration_timer, "pc_global_expiration_timer");
add_timer_func_list(pc_expiration_timer, "pc_expiration_timer"); add_timer_func_list(pc_expiration_timer, "pc_expiration_timer");
add_timer_func_list(pc_autotrade_timer, "pc_autotrade_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 DAMAGELOG_SIZE_PC 100 /// Damage log
#define MAX_SPIRITBALL 15 /// Max spirit balls #define MAX_SPIRITBALL 15 /// Max spirit balls
#define MAX_DEVOTION 5 /// Max Devotion slots #define MAX_DEVOTION 5 /// Max Devotion slots
#define MAX_SPIRITCHARM 10 /// Max spirit charms
#define BANK_VAULT_VAR "#BANKVAULT" #define BANK_VAULT_VAR "#BANKVAULT"
@ -456,8 +457,9 @@ struct map_session_data {
int8 spiritball, spiritball_old; int8 spiritball, spiritball_old;
int spirit_timer[MAX_SPIRITBALL]; 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. short spiritcharm; //No. of spirit
int talisman_timer[ELE_POISON+1][10]; int spiritcharm_type; //Spirit type
int spiritcharm_timer[MAX_SPIRITCHARM];
unsigned char potion_success_counter; //Potion successes in row counter unsigned char potion_success_counter; //Potion successes in row counter
unsigned char mission_count; //Stores the bounty kill count for TK_MISSION 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); 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_addspiritcharm(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_delspiritcharm(struct map_session_data *sd, int count, int type);
void pc_baselevelchanged(struct map_session_data *sd); 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; i = 0;
if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m) || (sd && sd->duel_group && sd->duel_group == dstsd->duel_group)) && 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] ((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]
if (dstsd->spiritball > 0) {
i = dstsd->spiritball * 7; i = dstsd->spiritball * 7;
pc_delspiritball(dstsd,dstsd->spiritball,0); 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] } 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; i = 2 * dstmd->level;
mob_target(dstmd,src,0); mob_target(dstmd,src,0);
@ -9445,14 +9451,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break; break;
case SR_ASSIMILATEPOWER: case SR_ASSIMILATEPOWER:
if( flag&1 ) { if (flag&1) {
i = 0; i = 0;
if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) {
{ if (dstsd->spiritball > 0) {
i = dstsd->spiritball; //1%sp per spiritball. i = dstsd->spiritball;
pc_delspiritball(dstsd, dstsd->spiritball, 0); pc_delspiritball(dstsd,dstsd->spiritball,0);
} }
if( i ) status_percent_heal(src, 0, i); 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);
clif_skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0); clif_skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0);
} else { } else {
clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); 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_HYOUHU_HUBUKI:
case KO_KAZEHU_SEIRAN: case KO_KAZEHU_SEIRAN:
case KO_DOHU_KOUKAI: case KO_DOHU_KOUKAI:
if(sd) { if (sd) {
int i_tal, ttype = skill_get_ele(skill_id, skill_lv); int type = 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); clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
if( i_tal < 6 ) pc_addspiritcharm(sd,skill_get_time(skill_id,skill_lv),MAX_SPIRITCHARM,type);
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);
} }
break; break;
case KO_ZANZOU: 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; limit = ((sd ? pc_checkskill(sd,GN_DEMONIC_FIRE) : 1) + 1) * limit;
break; break;
case KO_ZENKAI: case KO_ZENKAI:
if( sd ){ if (sd && sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) {
ARR_FIND(1, 6, i, sd->talisman[i] > 0); val1 = sd->spiritcharm;
if( i < 5 ){ val2 = sd->spiritcharm_type;
val1 = sd->talisman[i]; // no. of aura limit = 6000 * val1;
val2 = i; // aura type subunt = sd->spiritcharm_type - 1;
limit += val1 * 1000; pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type);
subunt = i - 1;
pc_del_talisman(sd, sd->talisman[i], i);
}
} }
break; break;
case HW_GRAVITATION: 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_HYOUHU_HUBUKI:
case KO_KAZEHU_SEIRAN: case KO_KAZEHU_SEIRAN:
case KO_DOHU_KOUKAI: case KO_DOHU_KOUKAI:
{ if (sd->spiritcharm_type == skill_get_ele(skill_id,skill_lv) && sd->spiritcharm >= MAX_SPIRITCHARM) {
int ttype = skill_get_ele(skill_id, skill_lv); clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0);
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; return false;
} }
}
break; break;
case KO_KAIHOU: case KO_KAIHOU:
case KO_ZENKAI: case KO_ZENKAI:
ARR_FIND(1, 6, i, sd->talisman[i] > 0); if (sd->spiritcharm_type == CHARM_TYPE_NONE || sd->spiritcharm <= 0) {
if( i > 4 ) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0);
clif_skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0);
return false; return false;
} }
break; break;

View File

@ -9614,7 +9614,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC__ENERVATION: case SC__ENERVATION:
val2 = 20 + 10 * val1; // ATK Reduction 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; break;
case SC__GROOMY: case SC__GROOMY:
val2 = 20 + 10 * val1; // ASPD 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); guild_send_memberinfoshort(sd,0);
pc_cleareventtimer(sd); pc_cleareventtimer(sd);
pc_inventory_rental_clear(sd); pc_inventory_rental_clear(sd);
pc_delspiritball(sd,sd->spiritball,1); pc_delspiritball(sd, sd->spiritball, 1);
pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type);
for(i = 1; i < 5; i++)
pc_del_talisman(sd, sd->talisman[i], i);
if( sd->reg ) { // Double logout already freed pointer fix... [Skotlex] if( sd->reg ) { // Double logout already freed pointer fix... [Skotlex]
aFree(sd->reg); aFree(sd->reg);