summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/battle.c132
-rw-r--r--src/map/map.h4
-rw-r--r--src/map/pc.c81
-rw-r--r--src/map/pc.h7
-rw-r--r--src/map/script.c19
-rw-r--r--src/map/skill.c123
-rw-r--r--src/map/status.c34
-rw-r--r--src/map/status.h4
8 files changed, 267 insertions, 137 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index 01f4c9b67..381dcd67e 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1658,26 +1658,24 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
break;
}
- if(sd)
+ if( sd )
{
if (skill_num && (i = pc_skillatk_bonus(sd, skill_num)))
ATK_ADDRATE(i);
- if(skill_num != PA_SACRIFICE && skill_num != MO_INVESTIGATE &&
- skill_num != CR_GRANDCROSS && skill_num != NPC_GRANDDARKNESS &&
- skill_num != PA_SHIELDCHAIN
- && !flag.cri)
- { //Elemental/Racial adjustments
- if(sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
+ if( skill_num != PA_SACRIFICE && skill_num != MO_INVESTIGATE && skill_num != CR_GRANDCROSS && skill_num != NPC_GRANDDARKNESS && skill_num != PA_SHIELDCHAIN && !flag.cri )
+ { //Elemental/Racial adjustments
+ if( sd->right_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
sd->right_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
sd->right_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))
)
flag.pdef = 1;
- if(sd->left_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
+ if( sd->left_weapon.def_ratio_atk_ele & (1<<tstatus->def_ele) ||
sd->left_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))
- ) { //Pass effect onto right hand if configured so. [Skotlex]
+ )
+ { //Pass effect onto right hand if configured so. [Skotlex]
if (battle_config.left_cardfix_to_right && flag.rh)
flag.pdef = 1;
else
@@ -1707,6 +1705,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
}
}
+ if( sc && sc->count && sc->data[SC_DEFRATIOATK] && skill_num != PA_SACRIFICE && skill_num != CR_GRANDCROSS && skill_num != NPC_GRANDDARKNESS && skill_num != PA_SHIELDCHAIN && !flag.cri )
+ flag.pdef = flag.pdef2 = sc->data[SC_DEFRATIOATK]->val1; // Occult Impact Effect
+
if (!flag.idef || !flag.idef2)
{ //Defense reduction
short vit_def;
@@ -1875,7 +1876,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
}
//Card Fix, sd side
- if ((wd.damage || wd.damage2) && !(nk&NK_NO_CARDFIX_ATK))
+ if( (wd.damage || wd.damage2) && !(nk&NK_NO_CARDFIX_ATK) )
{
int cardfix = 1000, cardfix_ = 1000;
int t_race2 = status_get_race2(target);
@@ -1887,8 +1888,12 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
- } else { //Melee attack
- if(!battle_config.left_cardfix_to_right)
+ if( tstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN])/100;
+ }
+ else
+ { // Melee attack
+ if( !battle_config.left_cardfix_to_right )
{
cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100;
if (!(nk&NK_NO_ELEFIX))
@@ -1896,8 +1901,10 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
+ if( tstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN])/100;
- if (flag.lh)
+ if( flag.lh )
{
cardfix_=cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100;
if (!(nk&NK_NO_ELEFIX))
@@ -1905,51 +1912,60 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
cardfix_=cardfix_*(100+sd->left_weapon.addsize[tstatus->size])/100;
cardfix_=cardfix_*(100+sd->left_weapon.addrace2[t_race2])/100;
cardfix_=cardfix_*(100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
+ if( tstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100;
}
- } else {
+ }
+ else
+ {
cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->left_weapon.addrace[tstatus->race])/100;
cardfix=cardfix*(100+sd->right_weapon.addele[tstatus->def_ele]+sd->left_weapon.addele[tstatus->def_ele])/100;
cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->left_weapon.addsize[tstatus->size])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2]+sd->left_weapon.addrace2[t_race2])/100;
cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100;
+ if( tstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100;
}
}
- for(i=0;i<ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate;i++) {
- if(sd->right_weapon.add_dmg[i].class_ == t_class) {
+ for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ )
+ {
+ if( sd->right_weapon.add_dmg[i].class_ == t_class )
+ {
cardfix=cardfix*(100+sd->right_weapon.add_dmg[i].rate)/100;
break;
}
}
- if (flag.lh)
+ if( flag.lh )
{
- for(i=0;i<ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate;i++) {
- if(sd->left_weapon.add_dmg[i].class_ == t_class) {
+ for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ )
+ {
+ if( sd->left_weapon.add_dmg[i].class_ == t_class )
+ {
cardfix_=cardfix_*(100+sd->left_weapon.add_dmg[i].rate)/100;
break;
}
}
}
- if(wd.flag&BF_LONG)
+ if( wd.flag&BF_LONG )
cardfix=cardfix*(100+sd->long_attack_atk_rate)/100;
- if (cardfix != 1000 || cardfix_ != 1000)
+ if( cardfix != 1000 || cardfix_ != 1000 )
ATK_RATE2(cardfix/10, cardfix_/10); //What happens if you use right-to-left and there's no right weapon, only left?
}
- if (skill_num == CR_SHIELDBOOMERANG || skill_num == PA_SHIELDCHAIN) { //Refine bonus applies after cards and elements.
+ if( skill_num == CR_SHIELDBOOMERANG || skill_num == PA_SHIELDCHAIN )
+ { //Refine bonus applies after cards and elements.
short index= sd->equip_index[EQI_HAND_L];
- if (index >= 0 &&
- sd->inventory_data[index] &&
- sd->inventory_data[index]->type == IT_ARMOR)
+ if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR )
ATK_ADD(10*sd->status.inventory[index].refine);
}
} //if (sd)
//Card Fix, tsd sid
- if (tsd && !(nk&NK_NO_CARDFIX_DEF))
+ if( tsd && !(nk&NK_NO_CARDFIX_DEF) )
{
short s_race2,s_class;
short cardfix=1000;
@@ -1957,24 +1973,29 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
s_race2 = status_get_race2(src);
s_class = status_get_class(src);
- if (!(nk&NK_NO_ELEFIX))
+ if( !(nk&NK_NO_ELEFIX) )
{
cardfix=cardfix*(100-tsd->subele[s_ele])/100;
- if (flag.lh && s_ele_ != s_ele)
+ if( flag.lh && s_ele_ != s_ele )
cardfix=cardfix*(100-tsd->subele[s_ele_])/100;
}
cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100;
cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;
cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
- for(i=0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++) {
- if(tsd->add_def[i].class_ == s_class) {
+ if( sstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
+
+ for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ )
+ {
+ if( tsd->add_def[i].class_ == s_class )
+ {
cardfix=cardfix*(100-tsd->add_def[i].rate)/100;
break;
}
}
- if(wd.flag&BF_SHORT)
+ if( wd.flag&BF_SHORT )
cardfix=cardfix*(100-tsd->near_attack_def_rate)/100;
else // BF_LONG (there's no other choice)
cardfix=cardfix*(100-tsd->long_attack_def_rate)/100;
@@ -1982,17 +2003,17 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if( tsd->sc.data[SC_DEF_RATE] )
cardfix=cardfix*(100-tsd->sc.data[SC_DEF_RATE]->val1)/100;
- if (cardfix != 1000)
+ if( cardfix != 1000 )
ATK_RATE(cardfix/10);
}
- if(flag.infdef)
+ if( flag.infdef )
{ //Plants receive 1 damage when hit
- if (flag.rh && (flag.hit || wd.damage>0))
+ if( flag.rh && (flag.hit || wd.damage>0) )
wd.damage = 1;
- if (flag.lh && (flag.hit || wd.damage2>0))
+ if( flag.lh && (flag.hit || wd.damage2>0) )
wd.damage2 = 1;
- if (!(battle_config.skill_min_damage&1))
+ if( !(battle_config.skill_min_damage&1) )
//Do not return if you are supposed to deal greater damage to plants than 1. [Skotlex]
return wd;
}
@@ -2430,9 +2451,9 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
MATK_RATE(cardfix/10);
}
- if (tsd && !(nk&NK_NO_CARDFIX_DEF))
- { //Target cards.
- short s_race2=status_get_race2(src);
+ if( tsd && !(nk&NK_NO_CARDFIX_DEF) )
+ { // Target cards.
+ short s_race2 = status_get_race2(src);
short s_class= status_get_class(src);
int cardfix=1000;
@@ -2442,6 +2463,9 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;
cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
+ if( sstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
+
for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) {
if(tsd->add_mdef[i].class_ == s_class) {
cardfix=cardfix*(100-tsd->add_mdef[i].rate)/100;
@@ -2662,7 +2686,8 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
}
}
- if(md.damage && tsd && !(nk&NK_NO_CARDFIX_DEF)){
+ if( md.damage && tsd && !(nk&NK_NO_CARDFIX_DEF) )
+ {
int cardfix = 10000;
int race2 = status_get_race2(src);
if (!(nk&NK_NO_ELEFIX))
@@ -2671,6 +2696,9 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
cardfix=cardfix*(100-tsd->subrace2[race2])/100;
cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100;
cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100;
+ if( sstatus->race != RC_DEMIHUMAN )
+ cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100;
+
cardfix=cardfix*(100-tsd->misc_def_rate)/100;
if(md.flag&BF_SHORT)
cardfix=cardfix*(100-tsd->near_attack_def_rate)/100;
@@ -3104,7 +3132,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
s_bl = src;
switch( target->type )
- { //Checks on actual target
+ { // Checks on actual target
case BL_PC:
if (((TBL_PC*)target)->invincible_timer != -1 || pc_isinvisible((TBL_PC*)target))
return -1; //Cannot be targeted yet.
@@ -3267,24 +3295,26 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
break;
}
- if ((flag&BCT_ALL) == BCT_ALL) { //All actually stands for all attackable chars
- if (target->type&BL_CHAR)
+ if( (flag&BCT_ALL) == BCT_ALL )
+ { //All actually stands for all attackable chars
+ if( target->type&BL_CHAR )
return 1;
else
return -1;
- } else
- if (flag == BCT_NOONE) //Why would someone use this? no clue.
+ }
+ else if( flag == BCT_NOONE ) //Why would someone use this? no clue.
return -1;
- if (t_bl == s_bl)
- { //No need for further testing.
+ if( t_bl == s_bl )
+ { //No need for further testing.
state |= BCT_SELF|BCT_PARTY|BCT_GUILD;
- if (state&BCT_ENEMY && strip_enemy)
+ if( state&BCT_ENEMY && strip_enemy )
state&=~BCT_ENEMY;
return (flag&state)?1:-1;
}
- if (map_flag_vs(m)) { //Check rivalry settings.
+ if( map_flag_vs(m) )
+ { //Check rivalry settings.
if (flag&(BCT_PARTY|BCT_ENEMY)) {
int s_party = status_get_party_id(s_bl);
if (
@@ -3331,10 +3361,10 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
}
}
- if (!state) //If not an enemy, nor a guild, nor party, nor yourself, it's neutral.
+ if( !state ) //If not an enemy, nor a guild, nor party, nor yourself, it's neutral.
state = BCT_NEUTRAL;
//Alliance state takes precedence over enemy one.
- else if (state&BCT_ENEMY && strip_enemy && state&(BCT_SELF|BCT_PARTY|BCT_GUILD))
+ else if( state&BCT_ENEMY && strip_enemy && state&(BCT_SELF|BCT_PARTY|BCT_GUILD) )
state&=~BCT_ENEMY;
return (flag&state)?1:-1;
diff --git a/src/map/map.h b/src/map/map.h
index 1504c773f..a401214c8 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -199,6 +199,7 @@ enum {
RC_DRAGON,
RC_BOSS,
RC_NONBOSS,
+ RC_NONDEMIHUMAN,
RC_MAX
};
@@ -305,7 +306,8 @@ enum _sp {
SP_HP_DRAIN_VALUE,SP_SP_DRAIN_VALUE, // 1079-1080
SP_WEAPON_ATK,SP_WEAPON_ATK_RATE, // 1081-1082
SP_DELAYRATE,SP_HP_DRAIN_RATE_RACE,SP_SP_DRAIN_RATE_RACE, // 1083-1085
- SP_IGNORE_MDEF_RATE, SP_IGNORE_DEF_RATE, //1086-1087
+ SP_IGNORE_MDEF_RATE,SP_IGNORE_DEF_RATE,SP_SKILL_HEAL2, //1086-1088
+
SP_RESTART_FULL_RECOVER=2000,SP_NO_CASTCANCEL,SP_NO_SIZEFIX,SP_NO_MAGIC_DAMAGE,SP_NO_WEAPON_DAMAGE,SP_NO_GEMSTONE, // 2000-2005
SP_NO_CASTCANCEL2,SP_NO_MISC_DAMAGE,SP_UNBREAKABLE_WEAPON,SP_UNBREAKABLE_ARMOR, SP_UNBREAKABLE_HELM, // 2006-2010
diff --git a/src/map/pc.c b/src/map/pc.c
index 08b511fc7..f094eafce 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -1395,22 +1395,30 @@ int pc_disguise(struct map_session_data *sd, int class_)
return 1;
}
-int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, struct script_code *script)
+int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, short target, struct script_code *script)
{
int i;
ARR_FIND(0, max, i, scripts[i].script == NULL);
- if (i == max) {
+ if( i == max )
+ {
ShowWarning("pc_autoscript_bonus: Reached max (%d) number of autoscripts per character!\n", max);
return 0;
}
+
scripts[i].script = script;
scripts[i].rate = rate;
+ scripts[i].target = target; // 0 = Script on Self 1 = Script on Target
//Auto-update flag value.
- if (!(flag&BF_RANGEMASK)) flag|=BF_SHORT|BF_LONG; //No range defined? Use both.
- if (!(flag&BF_WEAPONMASK)) flag|=BF_WEAPON; //No attack type defined? Use weapon.
- if (!(flag&BF_SKILLMASK)) {
- if (flag&(BF_MAGIC|BF_MISC)) flag|=BF_SKILL; //These two would never trigger without BF_SKILL
- if (flag&BF_WEAPON) flag|=BF_NORMAL;
+ if( !(flag&BF_RANGEMASK) )
+ flag|=BF_SHORT|BF_LONG; //No range defined? Use both.
+ if( !(flag&BF_WEAPONMASK) )
+ flag|=BF_WEAPON; //No attack type defined? Use weapon.
+ if( !(flag&BF_SKILLMASK) )
+ {
+ if( flag&(BF_MAGIC|BF_MISC) )
+ flag|=BF_SKILL; //These two would never trigger without BF_SKILL
+ if( flag&BF_WEAPON )
+ flag|=BF_NORMAL|BF_SKILL;
}
scripts[i].flag = flag;
return 1;
@@ -2408,7 +2416,7 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
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]
+ { // 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);
break;
}
@@ -2419,6 +2427,22 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
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("run_script: bonus2 bSkillHeal2 reached it's limit (%d 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;
@@ -5081,24 +5105,41 @@ int pc_resethate(struct map_session_data* sd)
int pc_skillatk_bonus(struct map_session_data *sd, int skill_num)
{
- int i;
- for (i = 0; i < ARRAYLENGTH(sd->skillatk) && sd->skillatk[i].id; i++)
+ int i, bonus = 0;
+ ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id && sd->skillatk[i].id == skill_num);
+ if( i < ARRAYLENGTH(sd->skillatk) && sd->skillatk[i].id )
+ bonus = sd->skillatk[i].val;
+ if( sd->sc.data[SC_SKILLATKBONUS] )
{
- if (sd->skillatk[i].id == skill_num)
- return sd->skillatk[i].val;
+ if( sd->sc.data[SC_SKILLATKBONUS]->val1 && sd->sc.data[SC_SKILLATKBONUS]->val1 == skill_num )
+ bonus += sd->sc.data[SC_SKILLATKBONUS]->val4;
+ if( sd->sc.data[SC_SKILLATKBONUS]->val2 && sd->sc.data[SC_SKILLATKBONUS]->val2 == skill_num )
+ bonus += sd->sc.data[SC_SKILLATKBONUS]->val4;
+ if( sd->sc.data[SC_SKILLATKBONUS]->val3 && sd->sc.data[SC_SKILLATKBONUS]->val3 == skill_num )
+ bonus += sd->sc.data[SC_SKILLATKBONUS]->val4;
}
- return 0;
+
+ return bonus;
}
int pc_skillheal_bonus(struct map_session_data *sd, int skill_num)
{
- int i;
- for (i = 0; i < ARRAYLENGTH(sd->skillheal) && sd->skillheal[i].id; i++)
- {
- if (sd->skillheal[i].id == skill_num)
- return sd->skillheal[i].val;
- }
- return 0;
+ int i, bonus = 0;
+
+ ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == skill_num);
+ if( i < ARRAYLENGTH(sd->skillheal) ) bonus += sd->skillheal[i].val;
+
+ return bonus;
+}
+
+int pc_skillheal2_bonus(struct map_session_data *sd, int skill_num)
+{
+ int i, bonus = 0;
+
+ ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == skill_num);
+ if( i < ARRAYLENGTH(sd->skillheal2) ) bonus += sd->skillheal2[i].val;
+
+ return bonus;
}
void pc_respawn(struct map_session_data* sd, uint8 clrtype)
diff --git a/src/map/pc.h b/src/map/pc.h
index 87ecd3279..a22f0c5ad 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -62,7 +62,7 @@ struct s_add_drop {
};
struct s_autoscript {
- unsigned short rate, flag;
+ unsigned short rate, flag, target;
struct script_code *script;
};
@@ -212,7 +212,7 @@ struct map_session_data {
struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills.
unsigned short id;
short val;
- } skillatk[MAX_PC_BONUS], skillheal[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS];
+ } skillatk[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS];
struct {
short value;
int rate;
@@ -555,7 +555,7 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd,
int pc_updateweightstatus(struct map_session_data *sd);
-int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, struct script_code *script);
+int pc_autoscript_add(struct s_autoscript *scripts, int max, short rate, short flag, short target, struct script_code *script);
void pc_autoscript_clear(struct s_autoscript *scripts, int max);
int pc_bonus(struct map_session_data*,int,int);
@@ -602,6 +602,7 @@ int pc_useitem(struct map_session_data*,int);
int pc_skillatk_bonus(struct map_session_data *sd, int skill_num);
int pc_skillheal_bonus(struct map_session_data *sd, int skill_num);
+int pc_skillheal2_bonus(struct map_session_data *sd, int skill_num);
void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int hp, unsigned int sp);
int pc_dead(struct map_session_data *sd,struct block_list *src);
diff --git a/src/map/script.c b/src/map/script.c
index 4dadb2775..5ce0c3409 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -6487,6 +6487,7 @@ BUILDIN_FUNC(bonus)
case SP_AUTOSPELL_WHENHIT:
case SP_SKILL_ATK:
case SP_SKILL_HEAL:
+ case SP_SKILL_HEAL2:
case SP_ADD_SKILL_BLOW:
case SP_CASTRATE:
// these bonuses support skill names
@@ -6535,7 +6536,7 @@ BUILDIN_FUNC(bonus)
/// Bonus script that has a chance of being executed on attack.
BUILDIN_FUNC(bonusautoscript)
{
- int rate, flag = 0;
+ int rate, flag = 0, target = 0;
const char *str;
struct script_code *script;
TBL_PC* sd;
@@ -6548,10 +6549,12 @@ BUILDIN_FUNC(bonusautoscript)
rate = script_getnum(st,3);
if( script_hasdata(st,4) )
flag = script_getnum(st,4);
+ if( script_hasdata(st,5) )
+ target = script_getnum(st,5);
script = parse_script(str, "autoscript bonus", 0, 0);
- if (!script)
+ if( !script )
return 1;
- if (!pc_autoscript_add(sd->autoscript, ARRAYLENGTH(sd->autoscript), rate, flag, script))
+ if( !pc_autoscript_add(sd->autoscript, ARRAYLENGTH(sd->autoscript), rate, flag, target, script) )
{
script_free_code(script);
return 1;
@@ -6561,7 +6564,7 @@ BUILDIN_FUNC(bonusautoscript)
/// Bonus script that has a chance of being executed when attacked.
BUILDIN_FUNC(bonusautoscript2)
{
- int rate, flag = 0;
+ int rate, flag = 0, target = 0;
const char *str;
struct script_code *script;
TBL_PC* sd;
@@ -6574,10 +6577,12 @@ BUILDIN_FUNC(bonusautoscript2)
rate = script_getnum(st,3);
if( script_hasdata(st,4) )
flag = script_getnum(st,4);
+ if( script_hasdata(st,5) )
+ target = script_getnum(st,5);
script = parse_script(str, "autoscript2 bonus", 0, 0);
if (!script)
return 1;
- if (!pc_autoscript_add(sd->autoscript2, ARRAYLENGTH(sd->autoscript2), rate, flag, script))
+ if (!pc_autoscript_add(sd->autoscript2, ARRAYLENGTH(sd->autoscript2), rate, flag, target, script))
{
script_free_code(script);
return 1;
@@ -13376,8 +13381,8 @@ struct script_function buildin_func[] = {
BUILDIN_DEF2(bonus,"bonus3","ivii"),
BUILDIN_DEF2(bonus,"bonus4","iviii"),
BUILDIN_DEF2(bonus,"bonus5","iviiii"),
- BUILDIN_DEF(bonusautoscript,"si?"),
- BUILDIN_DEF(bonusautoscript2,"si?"),
+ BUILDIN_DEF(bonusautoscript,"si??"),
+ BUILDIN_DEF(bonusautoscript2,"si??"),
BUILDIN_DEF(skill,"vi?"),
BUILDIN_DEF(addtoskill,"vi?"), // [Valaris]
BUILDIN_DEF(guildskill,"vi"),
diff --git a/src/map/skill.c b/src/map/skill.c
index 32f05a51a..579d27616 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -936,17 +936,18 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
}
//Auto-script when attacking
- if(sd && src != bl && sd->autoscript[0].script) {
+ if( sd && src != bl && sd->autoscript[0].script )
+ {
int i;
- for (i = 0; i < ARRAYLENGTH(sd->autoscript) && sd->autoscript[i].script; i++) {
-
+ for( i = 0; i < ARRAYLENGTH(sd->autoscript) && sd->autoscript[i].script; i++ )
+ {
if(!(sd->autoscript[i].flag&attack_type&BF_WEAPONMASK &&
sd->autoscript[i].flag&attack_type&BF_RANGEMASK &&
sd->autoscript[i].flag&attack_type&BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
- if (rand()%1000 > sd->autoscript[i].rate)
+ if( rand()%1000 > sd->autoscript[i].rate )
continue;
- run_script(sd->autoscript[i].script,0,sd->bl.id,0);
+ run_script(sd->autoscript[i].script,0,sd->autoscript[i].target?bl->id:src->id,0);
break; //Have only one script execute at a time.
}
}
@@ -1123,19 +1124,18 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
}
}
//Auto-script when attacked
- if(dstsd && !status_isdead(bl) && src != bl && dstsd->autoscript2[0].script &&
- !(skillid && skill_get_nk(skillid)&NK_NO_DAMAGE))
+ if( dstsd && !status_isdead(bl) && src != bl && dstsd->autoscript2[0].script && !(skillid && skill_get_nk(skillid)&NK_NO_DAMAGE) )
{
int i;
- for (i = 0; i < ARRAYLENGTH(dstsd->autoscript2) && dstsd->autoscript2[i].script; i++) {
-
+ for( i = 0; i < ARRAYLENGTH(dstsd->autoscript2) && dstsd->autoscript2[i].script; i++ )
+ {
if(!(dstsd->autoscript2[i].flag&attack_type&BF_WEAPONMASK &&
dstsd->autoscript2[i].flag&attack_type&BF_RANGEMASK &&
dstsd->autoscript2[i].flag&attack_type&BF_SKILLMASK))
continue; // one or more trigger conditions were not fulfilled
- if (rand()%1000 > dstsd->autoscript2[i].rate)
+ if( rand()%1000 > dstsd->autoscript2[i].rate )
continue;
- run_script(dstsd->autoscript2[i].script,0,dstsd->bl.id,0);
+ run_script(dstsd->autoscript2[i].script,0,dstsd->autoscript2[i].target?src->id:bl->id,0);
break; //Have only one script execute at a time.
}
}
@@ -2978,20 +2978,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
int heal = skill_calc_heal(src, bl, skilllv);
int heal_get_jobexp;
- if (status_isimmune(bl) || (dstmd && dstmd->class_ == MOBID_EMPERIUM))
+ if( status_isimmune(bl) || (dstmd && dstmd->class_ == MOBID_EMPERIUM) )
heal=0;
- if (sd) {
- if ((i = pc_skillheal_bonus(sd, skillid)))
+ if( sd )
+ {
+ if( (i = pc_skillheal_bonus(sd, skillid)) )
heal += heal * i / 100;
- if (sd && dstsd && sd->status.partner_id == dstsd->status.char_id &&
- (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0)
+ if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 )
heal = heal*2;
}
- if (tsc && tsc->count)
+ if( dstsd && (i = pc_skillheal2_bonus(dstsd, skillid)) )
+ heal += heal * i / 100;
+
+ if( tsc && tsc->count )
{
- if (tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS)
- ) { //Bounce back heal
+ if( tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS) )
+ { //Bounce back heal
if (--tsc->data[SC_KAITE]->val2 <= 0)
status_change_end(bl, SC_KAITE, -1);
if (src == bl)
@@ -4231,25 +4234,30 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AM_POTIONPITCHER:
{
int i,x,hp = 0,sp = 0,bonus=100;
- if(sd) {
+ if( sd )
+ {
x = skilllv%11 - 1;
i = pc_search_inventory(sd,skill_db[skillid].itemid[x]);
- if(i < 0 || skill_db[skillid].itemid[x] <= 0) {
+ if( i < 0 || skill_db[skillid].itemid[x] <= 0 )
+ {
clif_skill_fail(sd,skillid,0,0);
map_freeblock_unlock();
return 1;
}
- if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skillid].amount[x]) {
+ if( sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skillid].amount[x] )
+ {
clif_skill_fail(sd,skillid,0,0);
map_freeblock_unlock();
return 1;
}
- if(skillid == AM_BERSERKPITCHER) { //Does not override use-level, and cannot be used on bows.
- if (dstsd && (dstsd->status.base_level<(unsigned int)sd->inventory_data[i]->elv || dstsd->weapontype1 == W_BOW)) {
+ if( skillid == AM_BERSERKPITCHER )
+ { //Does not override use-level, and cannot be used on bows.
+ if( dstsd && (dstsd->status.base_level<(unsigned int)sd->inventory_data[i]->elv || dstsd->weapontype1 == W_BOW) )
+ {
clif_skill_fail(sd,skillid,0,0);
map_freeblock_unlock();
return 1;
- }
+ }
}
potion_flag = 1;
potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0;
@@ -4257,27 +4265,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
run_script(sd->inventory_data[i]->script,0,sd->bl.id,0);
pc_delitem(sd,i,skill_db[skillid].amount[x],0);
potion_flag = potion_target = 0;
- if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ALCHEMIST)
+ if( sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ALCHEMIST )
bonus += sd->status.base_level;
- if(potion_per_hp > 0 || potion_per_sp > 0) {
+ if( potion_per_hp > 0 || potion_per_sp > 0 )
+ {
hp = tstatus->max_hp * potion_per_hp / 100;
hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000;
- if(dstsd) {
+ if( dstsd )
+ {
sp = dstsd->status.max_sp * potion_per_sp / 100;
sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000;
}
}
- else {
- if(potion_hp > 0) {
+ else
+ {
+ if( potion_hp > 0 )
+ {
hp = potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000;
hp = hp * (100 + (tstatus->vit<<1)) / 100;
- if(dstsd)
+ if( dstsd )
hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
}
- if(potion_sp > 0) {
+ if( potion_sp > 0 )
+ {
sp = potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000;
sp = sp * (100 + (tstatus->int_<<1)) / 100;
- if(dstsd)
+ if( dstsd )
sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100;
}
}
@@ -4288,27 +4301,33 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
sp += sp * sd->itemgrouphealrate[IG_POTION] / 100;
}
- if ((i = pc_skillheal_bonus(sd, skillid)))
+ if( (i = pc_skillheal_bonus(sd, skillid)) )
{
hp += hp * i / 100;
sp += sp * i / 100;
}
}
- else {
+ else
+ {
hp = (1 + rand()%400) * (100 + skilllv*10) / 100;
hp = hp * (100 + (tstatus->vit<<1)) / 100;
- if(dstsd)
+ if( dstsd )
hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100;
}
- if (tsc && tsc->data[SC_CRITICALWOUND])
+ if( dstsd && (i = pc_skillheal2_bonus(dstsd, skillid)) )
+ {
+ hp += hp * i / 100;
+ sp += sp * i / 100;
+ }
+ if( tsc && tsc->data[SC_CRITICALWOUND] )
{
hp -= hp * tsc->data[SC_CRITICALWOUND]->val2 / 100;
sp -= sp * tsc->data[SC_CRITICALWOUND]->val2 / 100;
}
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- if(hp > 0 || (skillid == AM_POTIONPITCHER && sp <= 0))
+ if( hp > 0 || (skillid == AM_POTIONPITCHER && sp <= 0) )
clif_skill_nodamage(NULL,bl,AL_HEAL,hp,1);
- if(sp > 0)
+ if( sp > 0 )
clif_skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1);
status_heal(bl,hp,sp,0);
}
@@ -5295,6 +5314,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
i = skill_calc_heal( src, bl, 1+rand()%skilllv);
if (sd && (rnd = pc_skillheal_bonus(sd, skillid)) > 0)
i += i * rnd / 100;
+ if (dstsd && (rnd = pc_skillheal2_bonus(dstsd, skillid)) > 0)
+ i += i * rnd / 100;
//Eh? why double skill packet?
clif_skill_nodamage(src,bl,AL_HEAL,i,1);
clif_skill_nodamage(src,bl,skillid,i,1);
@@ -6981,6 +7002,9 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
if( tsc->data[SC_CRITICALWOUND] )
heal -= heal * tsc->data[SC_CRITICALWOUND]->val2 / 100;
}
+ if( tsd )
+ heal += heal * pc_skillheal2_bonus(tsd, sg->skill_id) / 100;
+
if( bl->type == BL_MER )
heal /= 2;
if( status_isimmune(bl) )
@@ -8445,35 +8469,42 @@ int skill_check_condition(struct map_session_data* sd, short skill, short lv, in
*------------------------------------------*/
int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
{
- int time = skill_get_cast(skill_id, skill_lv);
+ int time = skill_get_cast(skill_id, skill_lv);
struct map_session_data *sd;
+ struct status_change *sc;
nullpo_retr(0, bl);
sd = BL_CAST(BL_PC, bl);
+ sc = status_get_sc(bl);
// calculate base cast time (reduced by dex)
- if (!(skill_get_castnodex(skill_id, skill_lv)&1)) {
+ if( !(skill_get_castnodex(skill_id, skill_lv)&1) )
+ {
int scale = battle_config.castrate_dex_scale - status_get_dex(bl);
- if (scale > 0) // not instant cast
+ if( scale > 0 ) // not instant cast
time = time * scale / battle_config.castrate_dex_scale;
else return 0; // instant cast
}
// calculate cast time reduced by item/card bonuses
- if (!(skill_get_castnodex(skill_id, skill_lv)&4) && sd)
+ if( !(skill_get_castnodex(skill_id, skill_lv)&4) && sd )
{
int i;
- if (sd->castrate != 100)
+ if( sd->castrate != 100 )
time = time * sd->castrate / 100;
- for(i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++)
+ for( i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++ )
{
- if (sd->skillcast[i].id == skill_id)
+ if( sd->skillcast[i].id == skill_id )
{
time+= time * sd->skillcast[i].val / 100;
break;
}
}
}
+
+ if( sc && sc->count && sc->data[SC_SKILLCASTRATE] && sc->data[SC_SKILLCASTRATE]->val1 == skill_id )
+ time += time * sc->data[SC_SKILLCASTRATE]->val2 / 100;
+
// config cast time multiplier
if (battle_config.cast_rate != 100)
time = time * battle_config.cast_rate / 100;
diff --git a/src/map/status.c b/src/map/status.c
index fcfc0fb7f..67f4a7c85 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -1754,6 +1754,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
+ sizeof(sd->addeff2)
+ sizeof(sd->skillatk)
+ sizeof(sd->skillheal)
+ + sizeof(sd->skillheal2)
+ sizeof(sd->hp_loss)
+ sizeof(sd->sp_loss)
+ sizeof(sd->hp_regen)
@@ -5102,6 +5103,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
return 0;
break;
case SC_HPREGEN:
+ case SC_HPDRAIN:
case SC_SPREGEN:
case SC_BOSSMAPINFO:
case SC_STUN:
@@ -5432,6 +5434,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
tick = 10000;
break;
case SC_HPREGEN:
+ case SC_HPDRAIN:
case SC_SPREGEN:
if( val1 == 0 ) return 0;
// val1 = heal percent/amout
@@ -7094,6 +7097,17 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data)
}
break;
+ case SC_KNOWLEDGE:
+ if (!sd) break;
+ if(bl->m == sd->feel_map[0].m ||
+ bl->m == sd->feel_map[1].m ||
+ bl->m == sd->feel_map[2].m)
+ { //Timeout will be handled by pc_setpos
+ sce->timer = INVALID_TIMER;
+ return 0;
+ }
+ break;
+
case SC_BLEEDING:
if (--(sce->val4) >= 0) {
int flag;
@@ -7107,14 +7121,16 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data)
}
break;
- case SC_KNOWLEDGE:
- if (!sd) break;
- if(bl->m == sd->feel_map[0].m ||
- bl->m == sd->feel_map[1].m ||
- bl->m == sd->feel_map[2].m)
- { //Timeout will be handled by pc_setpos
- sce->timer = INVALID_TIMER;
- return 0;
+ case SC_HPDRAIN:
+ if( --(sce->val4) >= 0 )
+ {
+ int flag, hp = (sce->val1 < 0) ? (int)(status->max_hp * -1 * sce->val1 / 100.) : sce->val1;
+ map_freeblock_lock();
+ status_fix_damage(NULL, bl, hp, 0);
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( flag ) return 0;
+ sc_timer_next((sce->val2 * 1000) + tick, status_change_timer, bl->id, data);
}
break;
@@ -7130,7 +7146,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data)
sp = (sce->val1 < 0) ? (int)(sd->status.max_sp * -1 * sce->val1 / 100.) : sce->val1 ;
status_heal(bl, hp, sp, 2);
- sc_timer_next((sce->val2 * 1000) + tick, status_change_timer, bl->id, data );
+ sc_timer_next((sce->val2 * 1000) + tick, status_change_timer, bl->id, data);
return 0;
}
break;
diff --git a/src/map/status.h b/src/map/status.h
index b4b6dde61..d3301bd37 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -305,6 +305,10 @@ typedef enum sc_type {
SC_MERC_QUICKEN,
SC_REBIRTH,
+ SC_SKILLCASTRATE, //285
+ SC_DEFRATIOATK,
+ SC_HPDRAIN,
+ SC_SKILLATKBONUS,
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
} sc_type;