summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorL0neW0lf.eAthena <L0neW0lf.eAthena@54d463be-8e91-2dee-dedb-b68131a5f0ec>2011-10-26 19:44:18 +0000
committerL0neW0lf.eAthena <L0neW0lf.eAthena@54d463be-8e91-2dee-dedb-b68131a5f0ec>2011-10-26 19:44:18 +0000
commitb6620108c8dc2b0e394462a7d32cc77a446dddee (patch)
tree15769dda2b1454cda132c9b2409237a63bc975b9
parent8c95a8ceb2891c898b80df3ce002351f5a89dd03 (diff)
downloadhercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.gz
hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.bz2
hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.tar.xz
hercules-b6620108c8dc2b0e394462a7d32cc77a446dddee.zip
* Implemented first version of rebalanced Rune Knight skills.
* Implemented the rebalancing of most Archbishop skills. * As a result, merged r14979 from trunk. (act/notify packet update) * Added pc_isUseitem_check_runeskill care of Meyrawr (blocks rune usage based on skill delay.) * Added more status effects that do NOT save on log out. A whole slew of them. * Now only level 11 Dec. AGI will take the new config settings into account. * Fixed Level 11 Dec. AGI duration faux pas, where it was multiplying it by 100. * Added script command: setdragon: See documentation for details. * Added script command: successruneuse: Will return 0 or 1. Handles runestone backfire effects. * Modified script command: produce, now accepts <item id> as a second parameter. * Corrected message that is displayed when attempting to generate items when that item has a limit. * GM Item commands will no longer display 'Item created' messages on failure. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/renewal@14983 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--Changelog-Renewal.txt13
-rw-r--r--conf/battle/items.conf8
-rw-r--r--src/char/char.c2
-rw-r--r--src/char_sql/char.c2
-rw-r--r--src/map/atcommand.c6
-rw-r--r--src/map/battle.c204
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/clif.c73
-rw-r--r--src/map/clif.h3
-rw-r--r--src/map/map.c54
-rw-r--r--src/map/mob.c2
-rw-r--r--src/map/pc.c82
-rw-r--r--src/map/pc.h7
-rw-r--r--src/map/script.c134
-rw-r--r--src/map/skill.c276
-rw-r--r--src/map/status.c235
-rw-r--r--src/map/status.h39
-rw-r--r--src/map/unit.c2
18 files changed, 1029 insertions, 115 deletions
diff --git a/Changelog-Renewal.txt b/Changelog-Renewal.txt
index 97cd2639c..2efabfd33 100644
--- a/Changelog-Renewal.txt
+++ b/Changelog-Renewal.txt
@@ -1,5 +1,18 @@
Date Added
+2011/10/26
+ * Rev. 14982 Implemented first version of rebalanced Rune Knight skills. [L0ne_W0lf]
+ * Implemented the rebalancing of most Archbishop skills.
+ * As a result, merged r14979 from trunk. (act/notify packet update)
+ * Added pc_isUseitem_check_runeskill care of Meyrawr (blocks rune usage based on skill delay.)
+ * Added more status effects that do NOT save on log out. A whole slew of them.
+ * Now only level 11 Dec. AGI will take the new config settings into account.
+ * Fixed Level 11 Dec. AGI duration faux pas, where it was multiplying it by 100.
+ * Added script command: setdragon: See documentation for details.
+ * Added script command: successruneuse: Will return 0 or 1. Handles runestone backfire effects.
+ * Modified script command: produce, now accepts <item id> as a second parameter.
+ * Corrected message that is displayed when attempting to generate items when that item has a limit.
+ * GM Item commands will no longer display 'Item created' messages on failure.
2011/10/07
* Merged changes from trunk [14895:14966/trunk]. [Ai4rei]
2011/09/30
diff --git a/conf/battle/items.conf b/conf/battle/items.conf
index 9dc7ca314..200241ca6 100644
--- a/conf/battle/items.conf
+++ b/conf/battle/items.conf
@@ -87,3 +87,11 @@ gtb_sc_immunity: 50
// NOTE: Different cards that grant the same skill will both
// always work independently of each other regardless of setting.
autospell_stacking: no
+
+// Rune consumption is blocked by the skill's cooldown (note 1)
+rune_block_by_skill: yes
+
+// Rune consumption is blocked by previously activated status effect (Note 1)
+// associated with the skill the rune stone being used would cast.
+// ie: if SC_REFRESH is active, then the Nosiege Runestone is unuseable.
+rune_block_by_status: no
diff --git a/src/char/char.c b/src/char/char.c
index dfcbc9230..0f23744c0 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -1828,7 +1828,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
WBUFW(buf,52) = p->class_;
WBUFW(buf,54) = p->hair;
- WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
+ WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
WBUFW(buf,58) = p->base_level;
WBUFW(buf,60) = min(p->skill_point, INT16_MAX);
WBUFW(buf,62) = p->head_bottom;
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 0654be60a..30800d95b 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -1626,7 +1626,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
WBUFW(buf,52) = p->class_;
WBUFW(buf,54) = p->hair;
- WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
+ WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
WBUFW(buf,58) = p->base_level;
WBUFW(buf,60) = min(p->skill_point, INT16_MAX);
WBUFW(buf,62) = p->head_bottom;
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 5ccf14ea2..b1a395afa 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -1710,7 +1710,8 @@ ACMD_FUNC(item)
if(log_config.enable_logs&0x400)
log_pick_pc(sd, "A", item_id, number, NULL);
- clif_displaymessage(fd, msg_txt(18)); // Item created.
+ if (!flag)
+ clif_displaymessage(fd, msg_txt(18)); // Item created.
return 0;
}
@@ -1785,7 +1786,8 @@ ACMD_FUNC(item2)
if(log_config.enable_logs&0x400)
log_pick_pc(sd, "A", item_tmp.nameid, number, &item_tmp);
- clif_displaymessage(fd, msg_txt(18)); // Item created.
+ if (!flag)
+ clif_displaymessage(fd, msg_txt(18)); // Item created.
} else {
clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
return -1;
diff --git a/src/map/battle.c b/src/map/battle.c
index b0e42a7c7..f338a50bb 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -361,7 +361,26 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1);
return 0;
}
-
+
+ if((sce=sc->data[SC_MILLENNIUMSHIELD]) && damage > 0) {
+ if(sce->val2 > 0)
+ {
+ sce->val3 -= damage;
+ if( sce->val3 <= 0 )
+ { // Reduce remaining shields and create new one.
+ sc_start(bl,SC_STUN,15,0,1000);
+ sce->val3 = 1000;
+ sce->val2--;
+ if( sd )
+ clif_millenniumshield(sd,sce->val2);
+ }
+
+ damage = 0; // Nullify damage even if shield is destroyed.
+ }
+ if(sce->val2 <= 0)
+ status_change_end(bl, SC_MILLENNIUMSHIELD, INVALID_TIMER);
+ }
+
if(sc->data[SC_DODGE] && !sc->opt1 &&
(flag&BF_LONG || sc->data[SC_SPURT])
&& rand()%100 < 20) {
@@ -415,7 +434,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
}
//Finally damage reductions....
- if( sc->data[SC_ASSUMPTIO] )
+ if( sc->data[SC_ASSUMPTIO] && skill_num != RK_DRAGONBREATH )
{
if( map_flag_vs(bl->m) )
damage = damage*2/3; //Receive 66% damage
@@ -428,10 +447,11 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
damage=damage*(100-sc->data[SC_DEFENDER]->val2)/100;
if(sc->data[SC_ADJUSTMENT] &&
- (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
+ (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) &&
+ skill_num != RK_DRAGONBREATH)
damage -= 20*damage/100;
- if(sc->data[SC_FOGWALL]) {
+ if(sc->data[SC_FOGWALL] && skill_num != RK_DRAGONBREATH) {
if(flag&BF_SKILL) //25% reduction
damage -= 25*damage/100;
else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
@@ -493,7 +513,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
//Finally Kyrie because it may, or not, reduce damage to 0.
if((sce = sc->data[SC_KYRIE]) && damage > 0){
sce->val2-=damage;
- if(flag&BF_WEAPON || skill_num == TF_THROWSTONE){
+ if(flag&BF_WEAPON || skill_num == TF_THROWSTONE || skill_num == RK_DRAGONBREATH){
if(sce->val2>=0)
damage=0;
else
@@ -503,6 +523,13 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
status_change_end(bl, SC_KYRIE, INVALID_TIMER);
}
+ if((sce = sc->data[SC_STONEHARDSKIN]) && damage > 0)
+ {
+ sce->val2-=damage; // Reduce Stone Skin's HP by damage taken.
+ if( sce->val2 <= 0 )
+ status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER);
+ }
+
if (!damage) return 0;
//Probably not the most correct place, but it'll do here
@@ -601,6 +628,7 @@ int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int dam
case PA_PRESSURE:
case HW_GRAVITATION:
case NJ_ZENYNAGE:
+ case RK_DRAGONBREATH:
break;
default:
if( flag&BF_SKILL )
@@ -662,6 +690,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama
case PA_PRESSURE:
case HW_GRAVITATION:
case NJ_ZENYNAGE:
+ case RK_DRAGONBREATH:
break;
default:
if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
@@ -743,10 +772,13 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
case W_1HSPEAR:
case W_2HSPEAR:
if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
- if(!pc_isriding(sd))
+ if(!pc_isriding(sd) && !pc_isdragon(sd))
damage += (skill * 4);
else
damage += (skill * 5);
+ // increase damage by level of KN_SPEARMASTERY * 10
+ if (pc_checkskill(sd,RK_DRAGONTRAINING) > 0)
+ damage += (skill * 10);
}
break;
case W_1HAXE:
@@ -990,7 +1022,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
wd.type=0; //Normal attack
wd.div_=skill_num?skill_get_num(skill_num,skill_lv):1;
wd.amotion=(skill_num && skill_get_inf(skill_num)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills.
- if(skill_num == KN_AUTOCOUNTER)
+ if(skill_num == KN_AUTOCOUNTER || skill_num == RK_DEATHBOUND)
wd.amotion >>= 1;
wd.dmotion=tstatus->dmotion;
wd.blewcount=skill_get_blewcount(skill_num,skill_lv);
@@ -1063,6 +1095,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
break;
case KN_AUTOCOUNTER:
+ case RK_DEATHBOUND:
wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL;
break;
@@ -1403,6 +1436,15 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if( (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish]
ATK_ADDRATE(2*skill*i);
}
+ if(sd->status.party_id && sc && sc->data[SC_FIGHTINGSPIRIT])
+ {
+ i = party_foreachsamemap(party_sub_count, sd, 0);
+ if( (sc->data[SC_FIGHTINGSPIRIT]->val2) > 0){
+ ATK_ADDRATE(7*i); //Caster gets full effect.
+ }else{
+ ATK_ADDRATE(7*i/4); //Party members get 1/4.
+ }
+ }
}
break;
} //End default case
@@ -1725,6 +1767,62 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
case NPC_VAMPIRE_GIFT:
skillratio += ((skill_lv-1)%5+1)*100;
break;
+ case RK_SONICWAVE:
+ skillratio += ((skill_lv + 5) * 100) * (1 + (status_get_lv(src) -100) / 200);
+ break;
+ case RK_HUNDREDSPEAR:
+ {
+ int weight = 1, dmg = 0;
+ if (sd) {
+ short index = sd->equip_index[EQI_HAND_R];
+
+ if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
+ weight = sd->inventory_data[index]->weight; //80% of weight
+ }
+
+ dmg = (600 + (skill_lv * 80) + (1000 - (weight>1000?1000:weight)) * ((1 + status_get_lv(src) - 100) / 200));
+
+ if(sd) // Add clashing spiral bonus damage (Skill level * 50% damage)
+ dmg += pc_checkskill(sd,LK_SPIRALPIERCE) * (dmg * 50 /100);
+
+ skillratio = dmg;
+ break;
+ }
+ case RK_WINDCUTTER:
+ skillratio += ((skill_lv + 2) * 50) * status_get_lv(src) / 100;
+ break;
+ case RK_IGNITIONBREAK:
+ {
+ int dmg = 300; // Base maximum damage at less than 3 cells.
+ i = distance_bl(src,target);
+ if( i > 7 )
+ dmg -= 100; // Greather than 7 cells. (200 damage)
+ else if( i > 3 )
+ dmg -= 50; // Greater than 3 cells, less than 7. (250 damage)
+
+ dmg = (dmg * skill_lv) * (1+ (status_get_lv(src) - 100) / 120);
+
+ // Elemental check, +100% damage if your element is fire.
+ if( sstatus->rhw.ele == ELE_FIRE )
+ dmg += skill_lv * 100 / 100;
+
+ skillratio = dmg;
+ break;
+ }
+ case RK_CRUSHSTRIKE:
+ if(sd)
+ {
+ short index = sd->equip_index[EQI_HAND_R];
+ if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
+ skillratio = (sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6) * 100) + sd->inventory_data[index]->atk + sd->inventory_data[index]->weight;
+ }
+ break;
+ case RK_STORMBLAST:
+ skillratio = ((sd?pc_checkskill(sd,RK_RUNEMASTERY):1) + (sstatus->int_ / 8)) * 100;
+ break;
+ case RK_PHANTOMTHRUST:
+ skillratio = ((skill_lv * 50) + (sd?pc_checkskill(sd,KN_SPEARMASTERY):0) * 10) * status_get_lv(src) / 150;
+ break;
case AB_DUPLELIGHT_MELEE:
skillratio += 10 * skill_lv;
break;
@@ -2302,18 +2400,50 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
wd.damage += md.damage;
}
- //SG_FUSION hp penalty [Komurka]
- if (sc && sc->data[SC_FUSION])
- {
- int hp= sstatus->max_hp;
- if (sd && tsd) {
- hp = 8*hp/100;
- if (100*sstatus->hp <= 20*sstatus->max_hp)
- hp = sstatus->hp;
- } else
- hp = 2*hp/100; //2% hp loss per hit
- status_zap(src, hp, 0);
- }
+ if ( sc )
+ { // I don't see the point in repeating the SC check now that there are more things that use it. [L0ne_W0lf]
+ if (sc->data[SC_FUSION])
+ { //SG_FUSION hp penalty [Komurka]
+ int hp= sstatus->max_hp;
+ if (sd && tsd) {
+ hp = 8*hp/100;
+ if (100*sstatus->hp <= 20*sstatus->max_hp)
+ hp = sstatus->hp;
+ } else
+ hp = 2*hp/100; //2% hp loss per hit
+ status_zap(src, hp, 0);
+ }
+
+ if(sc->data[SC_ENCHANTBLADE] && !skill_num && wd.flag&BF_SHORT )
+ {
+ if (tsc && tsc->data[SC_SAFETYWALL])
+ ; // Although this is suposed to be considered a magic atttack, Safety Wall still blocks it? May be impemented wrong.
+ else
+ {
+ struct Damage ebd = battle_calc_attack(BF_MAGIC,src,target,RK_ENCHANTBLADE,sc->data[SC_ENCHANTBLADE]->val1,wd.flag);
+ wd.damage += (sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100) * (status_get_lv(src) / 150) + sstatus->int_ + ebd.damage;
+ }
+ }
+
+ if(sc->data[SC_GIANTGROWTH] && !skill_num )
+ {
+ int rate = battle_config.equip_natural_break_rate;
+ rate += 10;
+ skill_break_equip(src, EQP_WEAPON, rate, BCT_SELF);
+ if( rand() % 100 <= 10 )
+ ATK_RATE(300);
+ }
+
+ if(sc->data[SC_STONEHARDSKIN] && !skill_num)
+ { // SC_STRIPWEAPON will reduce damage by 25% so piggyback off that since there is no offensive status for this.
+ int rate = battle_config.equip_natural_break_rate;
+ rate += 300; //chance to break gear, or reduce attack by 25% in hte case of monsters.
+ if( sd )
+ skill_break_equip(src,EQP_WEAPON,rate,BCT_ENEMY);
+ if (!sd && !(status_get_mode(src)&MD_BOSS))
+ status_change_start(src,SC_STRIPWEAPON,rate,0,0,0,0,10000,0);
+ }
+ }
return wd;
}
@@ -2526,17 +2656,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
skillratio += 100 +100*skill_lv +100*(skill_lv/2);
break;
case AB_JUDEX:
- skillratio += ((skill_lv < 5)?180 + 20 * skill_lv:300); // Possible RE-Formula
- if( status_get_lv(src) >= 100 )
- skillratio = skillratio * status_get_lv(src) / 100;
+ skillratio += ((skill_lv * 20) + 300) * status_get_lv(src) / 100;
break;
case AB_ADORAMUS:
- skillratio += 100 * (skill_lv + 5);
- if( status_get_lv(src) >= 100 )
- skillratio = skillratio * status_get_lv(src) / 100;
+ skillratio += ((skill_lv * 100) + 500) * status_get_lv(src) / 100;
break;
case AB_DUPLELIGHT_MAGIC:
- skillratio += 100 + 20 * skill_lv;
+ skillratio = 200 + 20 * skill_lv;
break;
}
@@ -2830,6 +2956,8 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
case NPC_EVILLAND:
md.damage = skill_calc_heal(src,target,skill_num,skill_lv,false);
break;
+ case RK_DRAGONBREATH:
+ md.damage = (sstatus->hp / 50 + sstatus->max_sp / 4) * (skill_lv * status_get_lv(src)/150) * (95 + 5 * (sd?pc_checkskill(sd,RK_DRAGONTRAINING):10)) / 100;
}
if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
@@ -3198,7 +3326,19 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
skill_addtimerskill(src,tick+status_get_adelay(src) / 2,target->id,0,0,AB_DUPLELIGHT_MAGIC,skilllv,BF_MAGIC,flag);
}
- rdamage = battle_calc_return_damage(target, damage, wd.flag);
+ if(tsc && tsc->data[SC_DEATHBOUND] && !is_boss(src) && map_check_dir(map_calc_dir(src,target->x,target->y),unit_getdir(target)))
+ {
+ int skilllv = tsc->data[SC_DEATHBOUND]->val1;
+ clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1);
+ rdamage = wd.damage * ((500 + 100*skilllv) / 100);
+ wd.damage = rdamage * 30 / 100;
+ status_zap(target, wd.damage, 0);
+ skill_blown(src, src, skill_get_blewcount(RK_DEATHBOUND,skilllv), unit_getdir(src), 0);
+ status_change_end(target,SC_DEATHBOUND,INVALID_TIMER);
+ }
+ else
+ rdamage = battle_calc_return_damage(target, damage, wd.flag);
+
if( rdamage > 0 )
{
rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0);
@@ -3259,6 +3399,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
}
}
}
+ if (sc && sc->data[SC_CRUSHSTRIKE])
+ {
+ skill_castend_damage_id(src, target, RK_CRUSHSTRIKE, 1, tick, flag);
+ status_change_end(src,SC_CRUSHSTRIKE, INVALID_TIMER);
+ }
if (sd) {
if (wd.flag & BF_WEAPON && src != target && damage > 0) {
if (battle_config.left_cardfix_to_right)
@@ -4055,10 +4200,13 @@ static const struct _battle_data {
{ "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, },
{ "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, },
{ "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, },
-//MVP Decrease AGI
+// MVP Decrease AGI
{ "max_decagi_lv", &battle_config.max_decagi_lv, 11, 1, INT_MAX, },
{ "max_decagi_dur", &battle_config.max_decagi_dur, 120000, 1, INT_MAX, },
{ "max_decagi", &battle_config.max_decagi, 50, 0, INT_MAX, },
+// Third jobs
+ { "rune_block_by_skill", &battle_config.rune_block_by_skill, 1, 0, 1, },
+ { "rune_block_by_status", &battle_config.rune_block_by_status, 0, 0, 1, },
};
diff --git a/src/map/battle.h b/src/map/battle.h
index 08a2a46f4..7570f77b7 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -499,6 +499,8 @@ extern struct Battle_Config
int max_decagi_lv;
int max_decagi_dur;
int max_decagi;
+ int rune_block_by_skill;
+ int rune_block_by_status;
} battle_config;
void do_init_battle(void);
diff --git a/src/map/clif.c b/src/map/clif.c
index db34d30ae..a8cfa48cd 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1193,6 +1193,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);
+ if(sd->sc.data[SC_MILLENNIUMSHIELD] && sd->sc.data[SC_MILLENNIUMSHIELD]->val2 > 0) // Ensure that we have shields to display.
+ clif_millenniumshield(sd,sd->sc.data[SC_MILLENNIUMSHIELD]->val2);
}
break;
case BL_MOB:
@@ -3819,8 +3821,8 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da
/*==========================================
* Sends a 'damage' packet (src performs action on dst)
- * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W
- * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L
+ * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W (ZC_NOTIFY_ACT)
+ * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L (ZC_NOTIFY_ACT2)
*
* type=00 damage [param1: total damage, param2: div, param3: assassin dual-wield damage]
* type=01 pick up item
@@ -3834,8 +3836,13 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da
*------------------------------------------*/
int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tick, int sdelay, int ddelay, int damage, int div, int type, int damage2)
{
- unsigned char buf[256];
+ unsigned char buf[33];
struct status_change *sc;
+#if PACKETVER < 20071113
+ const int cmd = 0x8a;
+#else
+ const int cmd = 0x2e1;
+#endif
nullpo_ret(src);
nullpo_ret(dst);
@@ -3849,12 +3856,13 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic
}
}
- WBUFW(buf,0)=0x8a;
+ WBUFW(buf,0)=cmd;
WBUFL(buf,2)=src->id;
WBUFL(buf,6)=dst->id;
WBUFL(buf,10)=tick;
WBUFL(buf,14)=sdelay;
WBUFL(buf,18)=ddelay;
+#if PACKETVER < 20071113
if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) {
WBUFW(buf,22)=damage?div:0;
WBUFW(buf,27)=damage2?div:0;
@@ -3864,20 +3872,35 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic
}
WBUFW(buf,24)=div;
WBUFB(buf,26)=type;
+#else
+ if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) {
+ WBUFL(buf,22)=damage?div:0;
+ WBUFL(buf,29)=damage2?div:0;
+ } else {
+ WBUFL(buf,22)=damage;
+ WBUFL(buf,29)=damage2;
+ }
+ WBUFW(buf,26)=div;
+ WBUFB(buf,28)=type;
+#endif
if(disguised(dst)) {
- clif_send(buf,packet_len(0x8a),dst,AREA_WOS);
+ clif_send(buf,packet_len(cmd),dst,AREA_WOS);
WBUFL(buf,6) = -dst->id;
- clif_send(buf,packet_len(0x8a),dst,SELF);
+ clif_send(buf,packet_len(cmd),dst,SELF);
} else
- clif_send(buf,packet_len(0x8a),dst,AREA);
+ clif_send(buf,packet_len(cmd),dst,AREA);
if(disguised(src)) {
WBUFL(buf,2) = -src->id;
if (disguised(dst))
WBUFL(buf,6) = dst->id;
if(damage > 0) WBUFW(buf,22) = -1;
+#if PACKETVER < 20071113
if(damage2 > 0) WBUFW(buf,27) = -1;
- clif_send(buf,packet_len(0x8a),src,SELF);
+#else
+ if(damage2 > 0) WBUFW(buf,29) = -1;
+#endif
+ clif_send(buf,packet_len(cmd),src,SELF);
}
//Return adjusted can't walk delay for further processing.
return clif_calc_walkdelay(dst,ddelay,type,damage+damage2,div);
@@ -8688,6 +8711,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if (sd->sc.option&OPTION_RIDING)
clif_status_load(&sd->bl, SI_RIDING, 1);
+ if (sd->sc.option&OPTION_DRAGON)
+ clif_status_load(&sd->bl, SI_RIDING, 1);
+
if(sd->status.manner < 0)
sc_start(&sd->bl,SC_NOCHAT,100,0,0);
@@ -8906,7 +8932,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
return;
}
- if (sd->sc.opt1 && sd->sc.opt1 == OPT1_STONEWAIT)
+ if (sd->sc.opt1 && (sd->sc.opt1 == OPT1_STONEWAIT || sd->sc.opt1 == OPT1_BURNING))
; //You CAN walk on this OPT1 value.
else if( sd->progressbar.npc_id )
clif_progressbar_abort(sd);
@@ -9156,7 +9182,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
if (sd->sc.count &&
(sd->sc.data[SC_TRICKDEAD] ||
sd->sc.data[SC_AUTOCOUNTER] ||
- sd->sc.data[SC_BLADESTOP]))
+ sd->sc.data[SC_BLADESTOP] ||
+ sd->sc.data[SC_DEATHBOUND]))
return;
pc_stop_walking(sd, 1);
@@ -9202,7 +9229,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
return;
}
- if (sd->ud.skilltimer != INVALID_TIMER || sd->sc.opt1)
+ if (sd->ud.skilltimer != INVALID_TIMER || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING))
break;
if (sd->sc.count && (
@@ -9498,6 +9525,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
if (sd->sc.count && (
sd->sc.data[SC_AUTOCOUNTER] ||
sd->sc.data[SC_BLADESTOP] ||
+ sd->sc.data[SC_DEATHBOUND] ||
(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
))
break;
@@ -9524,7 +9552,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
return;
}
- if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT)
+ if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING)
return;
//This flag enables you to use items while in an NPC. [Skotlex]
@@ -9563,7 +9591,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
if(sd->npc_id) {
if (sd->npc_id != sd->npc_item_flag)
return;
- } else if (sd->state.storage_flag || sd->sc.opt1)
+ } else if (sd->state.storage_flag || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING))
; //You can equip/unequip stuff while storage is open/under status changes
else if (pc_cant_act(sd))
return;
@@ -9919,7 +9947,7 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd)
void clif_parse_RemoveOption(int fd,struct map_session_data *sd)
{
//Can only remove Cart/Riding/Falcon.
- pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON));
+ pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON));
}
/*==========================================
@@ -14785,6 +14813,19 @@ void clif_search_store_info_click_ack(struct map_session_data* sd, short x, shor
WFIFOSET(fd,packet_len(0x83d));
}
+// Correct packet for RK_MILLENIUMSHIELD. Shows spirit spheres.
+void clif_millenniumshield(struct map_session_data *sd, int num)
+{
+#if PACKETVER >= 20081217
+ unsigned char buf[10];
+
+ WBUFW(buf,0)=0x440;
+ WBUFL(buf,2)=sd->bl.id;
+ WBUFW(buf,6)=num;
+ WBUFW(buf,8)=0;
+ clif_send(buf,packet_len(0x440),&sd->bl,AREA);
+#endif
+}
/// Parse function for packet debugging
void clif_parse_debug(int fd,struct map_session_data *sd)
@@ -15088,7 +15129,7 @@ static int packetdb_readdb(void)
//#0x02C0
0, 0, 0, 0, 0, 30, 30, 0, 0, 3, 0, 65, 4, 71, 10, 0,
0, 0, 0, 0, 29, 0, 6, -1, 10, 10, 3, 0, -1, 32, 6, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 59, 60, 8,
+ 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 59, 60, 8,
10, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//#0x0300
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -15116,7 +15157,7 @@ static int packetdb_readdb(void)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 25,
//#0x0440
- 0, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/src/map/clif.h b/src/map/clif.h
index 620ba0668..9d1207901 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -626,4 +626,7 @@ void clif_search_store_info_failed(struct map_session_data* sd, unsigned char re
void clif_open_search_store_info(struct map_session_data* sd);
void clif_search_store_info_click_ack(struct map_session_data* sd, short x, short y);
+// Third jobs
+void clif_millenniumshield(struct map_session_data *sd, int num);
+
#endif /* _CLIF_H_ */
diff --git a/src/map/map.c b/src/map/map.c
index 39077de6c..a4b419f65 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1584,6 +1584,9 @@ int map_quit(struct map_session_data *sd)
status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER);
status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER);
if (battle_config.debuff_on_logout&1) {
+ status_change_end(&sd->bl, SC_DECREASEAGI, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_AETERNA, INVALID_TIMER);
status_change_end(&sd->bl, SC_ORCISH, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPWEAPON, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPARMOR, INVALID_TIMER);
@@ -1591,6 +1594,8 @@ int map_quit(struct map_session_data *sd)
status_change_end(&sd->bl, SC_STRIPHELM, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXTREMITYFIST, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_JOINTBEAT, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_MINDBREAKER, INVALID_TIMER);
if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4)
status_change_end(&sd->bl, SC_REGENERATION, INVALID_TIMER);
//TO-DO Probably there are way more NPC_type negative status that are removed
@@ -1601,12 +1606,61 @@ int map_quit(struct map_session_data *sd)
}
if (battle_config.debuff_on_logout&2)
{
+ status_change_end(&sd->bl, SC_MAGNIFICAT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MAXIMIZEPOWER, INVALID_TIMER);
status_change_end(&sd->bl, SC_MAXOVERTHRUST, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_AURABLADE, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_PARRYING, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_CONCENTRATION, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_MAGICPOWER, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_EDP, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_TRUESIGHT, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_WINDWALK, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_MELTDOWN, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_CARTBOOST, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_MEMORIZE, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_DEVOTION, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_SACRIFICE, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEELBODY, INVALID_TIMER);
status_change_end(&sd->bl, SC_PRESERVE, INVALID_TIMER);
status_change_end(&sd->bl, SC_KAAHI, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_KAUPE, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_DOUBLECAST, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_SHRINK, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_SIGHTBLASTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_SPIRIT, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_KAITE, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_UTSUSEMI, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_BUNSINJYUTSU, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_SUITON, INVALID_TIMER);
+ // Third jobs
+ status_change_end(&sd->bl, SC_MILLENNIUMSHIELD, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_DEATHBOUND, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_REFRESH, INVALID_TIMER);
+ status_change_end(&sd->bl, SC_STONEHARDSKIN, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_HALLUCINATIONWALK_POSTDELAY, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_WEAPONBLOCKING_POSTDELAY, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_ROLLINGCUTTER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_ELECTRICSHOCKER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_WUGDASH, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_WUGBITE, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_CAMOUFLAGE, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_MAGNETICFIELD, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_SHADOWFORM, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_INVISIBILITY, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_RAISINGDRAGON, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_NOEQUIPACCESSARY, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_MANHOLE, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_DEEP_SLEEP, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_WARMER, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_GN_TRAINING_SWORD, INVALID_TIMER);
+ //status_change_end(&sd->bl, SC_GN_REMODELING_CART, INVALID_TIMER);
}
}
diff --git a/src/map/mob.c b/src/map/mob.c
index 5272b17e8..49ca6eb23 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -1311,7 +1311,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
return false;
// Abnormalities
- if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP])
+ if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING) || md->sc.data[SC_BLADESTOP])
{ //Should reset targets.
md->target_id = md->attacked_id = 0;
return false;
diff --git a/src/map/pc.c b/src/map/pc.c
index ff775be07..440c684f4 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -395,7 +395,7 @@ int pc_makesavestatus(struct map_session_data *sd)
//Only copy the Cart/Peco/Falcon options, the rest are handled via
//status change load/saving. [Skotlex]
- sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING);
+ sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON);
if (sd->sc.data[SC_JAILED])
{ //When Jailed, do not move last point.
@@ -3414,7 +3414,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
if( data->stack.inventory && amount > data->stack.amount )
{// item stack limitation
- return 5;
+ return 7;
}
w = data->weight*amount;
@@ -3694,7 +3694,6 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( nameid == 12243 && sd->md->db->lv < 80 )
return 0;
break;
-
case 12213: //Neuralizer
if( !map[sd->bl.m].flag.reset )
return 0;
@@ -3704,6 +3703,9 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL )
return 0; // Mercenary Scrolls
+ if (nameid >= 12725 && nameid <= 12733 && !pc_isUseitem_check_runeskill(sd, sd->status.inventory[n].nameid) )
+ return 0;
+
//added item_noequip.txt items check by Maya&[Lupus]
if (
(!map_flag_vs(sd->bl.m) && item->flag.no_equip&1) || // Normal
@@ -3742,6 +3744,45 @@ int pc_isUseitem(struct map_session_data *sd,int n)
return 1;
}
+
+int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid)
+{
+ struct {
+ int runeid;
+ int skillid;
+ } rune2skill_table[] = {
+ { 12725, RK_REFRESH },
+ { 12726, RK_CRUSHSTRIKE },
+ { 12727, RK_MILLENNIUMSHIELD },
+ { 12728, RK_VITALITYACTIVATION },
+ { 12729, RK_FIGHTINGSPIRIT },
+ { 12730, RK_ABUNDANCE },
+ { 12731, RK_GIANTGROWTH },
+ { 12732, RK_STORMBLAST },
+ { 12733, RK_STONEHARDSKIN },
+ };
+
+ int i;
+ int skillid;
+
+ nullpo_retr(0, sd);
+
+ ARR_FIND(0, ARRAYLENGTH(rune2skill_table), i, rune2skill_table[i].runeid == nameid);
+ if ( i == ARRAYLENGTH(rune2skill_table) ) {
+ ShowError("pc_isUseitem_check_runeskill: rune %d skill not found.\n", nameid);
+ return 0;
+ }
+
+ skillid = rune2skill_table[i].skillid;
+ if ( battle_config.rune_block_by_skill && skillnotok(skillid, sd) )
+ return 0;
+ if ( battle_config.rune_block_by_status && status_skill2sc(skillid) != SC_NONE && sd->sc.data[status_skill2sc(skillid)] )
+ return 0;
+
+ return 1;
+}
+
+
/*==========================================
* ƒAƒCƒeƒ€‚ðŽg‚¤
*------------------------------------------*/
@@ -5748,6 +5789,8 @@ int pc_resetskill(struct map_session_data* sd, int flag)
i &= ~OPTION_CART;
if( i&OPTION_FALCON && pc_checkskill(sd, HT_FALCON) )
i &= ~OPTION_FALCON;
+ if( i&OPTION_DRAGON && pc_checkskill(sd, KN_RIDING) ) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is.
+ i&=~OPTION_DRAGON;
if( i != sd->sc.option )
pc_setoption(sd, i);
@@ -6522,6 +6565,13 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
}
+ if (sd->sc.data[SC_VITALITYACTIVATION])
+ {
+ hp += hp * sd->sc.data[SC_VITALITYACTIVATION]->val2 / 100; //HP +50%
+ sp -= sp * sd->sc.data[SC_VITALITYACTIVATION]->val3 / 100; //SP -50%
+ }
+
+
return status_heal(&sd->bl, hp, sp, 1);
}
@@ -6676,6 +6726,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
i&=~OPTION_CART;
if(i&OPTION_FALCON && !pc_checkskill(sd, HT_FALCON))
i&=~OPTION_FALCON;
+ if(i&OPTION_DRAGON && !pc_checkskill(sd, KN_RIDING)) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is.
+ i&=~OPTION_DRAGON;
if(i != sd->sc.option)
pc_setoption(sd, i);
@@ -6804,12 +6856,16 @@ int pc_setoption(struct map_session_data *sd,int type)
sd->sc.option=type;
clif_changeoption(&sd->bl);
- if (type&OPTION_RIDING && !(p_type&OPTION_RIDING) && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
+ if (((type&OPTION_RIDING && !(p_type&OPTION_RIDING)) // Knight and Crusader/Royal Guard
+ || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON))) // Rune Knight Dragon
+ && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
{ //We are going to mount. [Skotlex]
clif_status_load(&sd->bl,SI_RIDING,1);
status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds.
}
- else if (!(type&OPTION_RIDING) && p_type&OPTION_RIDING && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
+ else if (((!(type&OPTION_RIDING) && p_type&OPTION_RIDING) //Knight and Crusader/Royal Guard
+ || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON)) // Rune Knight Dragon
+ && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
{ //We are going to dismount.
clif_status_load(&sd->bl,SI_RIDING,0);
status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds.
@@ -6927,6 +6983,22 @@ int pc_setriding(TBL_PC* sd, int flag)
}
/*==========================================
+ * Enable Riding Dragons for Rune Knight class.
+ *------------------------------------------*/
+int pc_setdragon(TBL_PC* sd, int flag, int color)
+{
+ int dragon[5] = {OPTION_DRAGON1,OPTION_DRAGON2,OPTION_DRAGON3,OPTION_DRAGON4,OPTION_DRAGON5};
+
+ if( flag ){
+ if( pc_checkskill(sd,KN_RIDING) > 0 ) //Possible to rent dragons without RK_DRAGONTRAINING; Source, iRO. (Bug?)
+ pc_setoption(sd, sd->sc.option|dragon[color]);
+ } else if( pc_isdragon(sd) ){
+ pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
+ }
+
+ return 0;
+}
+/*==========================================
* ƒAƒCƒeƒ€ƒhƒƒbƒv‰Â•s‰Â”»’è
*------------------------------------------*/
int pc_candrop(struct map_session_data *sd,struct item *item)
diff --git a/src/map/pc.h b/src/map/pc.h
index a49c4628e..4619af878 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -420,6 +420,8 @@ struct map_session_data {
unsigned int bg_id;
unsigned short user_font;
+ int produce_itemusedid; //used to determine the type of item used when creating items via script.
+
// temporary debugging of bug #3504
const char* delunit_prevfile;
int delunit_prevline;
@@ -526,7 +528,7 @@ enum equip_index {
#define pc_issit(sd) ( (sd)->vd.dead_sit == 2 )
#define pc_isidle(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
#define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
-#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || (sd)->sc.opt1 || (sd)->state.trading || (sd)->state.storage_flag )
+#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chatID = n )
#define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
@@ -539,6 +541,7 @@ enum equip_index {
#define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate )
#define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 )
#define pc_maxparameter(sd) ( ((sd)->class_&JOBL_3 ? ((sd)->class_&JOBL_BABY ? battle_config.max_baby_third_parameter : battle_config.max_third_parameter) : ((sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter)) )
+#define pc_isdragon(sd) ( (sd)->sc.option&OPTION_DRAGON )
#define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type)
#define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl)
@@ -664,6 +667,7 @@ int pc_equipitem(struct map_session_data*,int,int);
int pc_unequipitem(struct map_session_data*,int,int);
int pc_checkitem(struct map_session_data*);
int pc_useitem(struct map_session_data*,int);
+int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid);
int pc_skillatk_bonus(struct map_session_data *sd, int skill_num);
int pc_skillheal_bonus(struct map_session_data *sd, int skill_num);
@@ -682,6 +686,7 @@ int pc_setfalcon(struct map_session_data* sd, int flag);
int pc_setriding(struct map_session_data* sd, int flag);
int pc_changelook(struct map_session_data *,int,int);
int pc_equiplookall(struct map_session_data *sd);
+int pc_setdragon(struct map_session_data* sd, int flag, int color);
int pc_readparam(struct map_session_data*,int);
int pc_setparam(struct map_session_data*,int,int);
diff --git a/src/map/script.c b/src/map/script.c
index 881d2f082..0f3c09e1e 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -7426,7 +7426,7 @@ BUILDIN_FUNC(setoption)
flag = script_getnum(st,3);
else if( !option ){// Request to remove everything.
flag = 0;
- option = OPTION_CART|OPTION_FALCON|OPTION_RIDING;
+ option = OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON;
}
if( flag ){// Add option
if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay )
@@ -7542,7 +7542,7 @@ BUILDIN_FUNC(checkriding)
if( sd == NULL )
return 0;// no player attached, report source
- if( pc_isriding(sd) )
+ if( pc_isriding(sd) || pc_isdragon(sd) )
script_pushint(st, 1);
else
script_pushint(st, 0);
@@ -7571,6 +7571,31 @@ BUILDIN_FUNC(setriding)
return 0;
}
+/// Sets if the player is riding a dragon.
+/// <flag> defaults to 1
+/// <color> defaults to 0
+///
+/// setdragon <flag>{,<color>};
+/// setdragon <flag>;
+/// setdragon;
+BUILDIN_FUNC(setdragon)
+{
+ int flag = 1, color = 0;
+ TBL_PC* sd;
+
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;// no player attached, report source
+
+ if( script_hasdata(st,2) )
+ flag = script_getnum(st,2);
+ if( script_hasdata(st,3) )
+ color = cap_value(script_getnum(st,3),0,4);
+
+ pc_setdragon(sd, flag, color);
+ return 0;
+}
+
/// Sets the save point of the player.
///
/// save "<map name>",<x>,<y>
@@ -7762,6 +7787,28 @@ BUILDIN_FUNC(produce)
sd = script_rid2sd(st);
if( sd == NULL )
return 0;
+
+ if( script_hasdata(st,3) )
+ { // only used with Rune Knights RK_RUNEMASTERY as part of the calculation.
+ struct item_data* id = NULL;
+ struct script_data* data;
+
+ data = script_getdata(st,3);
+ get_val(st, data);
+
+ if( data_isstring(data) )
+ id = itemdb_searchname(conv_str(st, data));
+ else
+ id = itemdb_exists(conv_num(st, data));
+
+ if( id == NULL )
+ {
+ ShowError("buildin_produce: Invalid item '%s'.\n", script_getstr(st,3));
+ return 1;
+ }
+ else
+ sd->produce_itemusedid = id->nameid;
+ }
trigger=script_getnum(st,2);
clif_skill_produce_mix_list(sd, trigger);
@@ -14945,6 +14992,85 @@ BUILDIN_FUNC(searchstores)
return 0;
}
+/// Returns the successful use of a Rune Knight Runestone.
+///
+/// SuccessRuneUse()
+///
+BUILDIN_FUNC(successruneuse)
+{
+ struct item_data* id = NULL;
+ struct map_session_data* sd;
+ struct script_data* data;
+
+ if( ( sd = script_rid2sd(st) ) == NULL )
+ return 0; // no player attached, report source
+
+ data = script_getdata(st,2);
+ get_val(st, data); // convert into value in case of a variable
+
+ if( data_isstring(data) )
+ id = itemdb_searchname(conv_str(st, data));
+ else
+ id = itemdb_exists(conv_num(st, data));
+
+ if( id == NULL )
+ {
+ ShowError("buildin_successruneuse: Invalid item '%s'.\n", script_getstr(st,2));
+ script_pushint(st,0);
+ return 1;
+ }
+
+ if( (sd->class_&~(JOBL_UPPER|JOBL_BABY)) == MAPID_RUNE_KNIGHT )
+ {
+ int skilllv = pc_checkskill(sd,RK_RUNEMASTERY);
+ int i = (sd->status.dex + sd->status.luk ) / 20 + (skilllv?55+skilllv:0) + 30;
+
+ if (rand() % 100 < i)
+ script_pushint(st, 1);
+ else
+ {
+ script_pushint(st, 0);
+
+ i = rand() % 100; // reroll for fail effects
+ if( i < 3 )
+ {
+ long damage = (1000 * id->weight) - (sd->battle_status.mdef + sd->battle_status.mdef2);
+ clif_damage(&sd->bl, &sd->bl, gettick(), 0, 0, damage, 0, 0, 0);
+ status_damage(&sd->bl, &sd->bl, damage, 0, 0, 0);
+ }
+ else if( i < 13 )
+ { // Random status effect
+ struct {
+ sc_type type;
+ int duration;
+ } effects[] = {
+ { SC_FREEZE, 30000 },
+ { SC_STUN, 5000 },
+ { SC_SLEEP, 20000 },
+ { SC_SILENCE, 20000 },
+ { SC_BLIND, 20000 },
+ };
+ i = rand()%ARRAYLENGTH(effects); // redesignate i to random status effect+duration.
+ sc_start(&sd->bl, effects[i].type, 100, 1, effects[i].duration);
+ }
+ else if( i < 15 )
+ pc_randomwarp(sd, CLR_TELEPORT);
+ else if( i < 18 )
+ ; // Unknown effect, however weight of the item used is taken into account.
+ else if( i < 19 )
+ {
+ if (!status_isimmune(&sd->bl))
+ status_percent_heal(&sd->bl, 100, 100);
+ }
+ else if( i >= 20 )
+ ; // Unknown effect
+ }
+ }
+ else
+ script_pushint(st, 0);
+
+ return 0;
+}
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
@@ -15054,6 +15180,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(setfalcon,"?"),
BUILDIN_DEF(checkfalcon,""),
BUILDIN_DEF(setriding,"?"),
+ BUILDIN_DEF(setdragon,"??"),
BUILDIN_DEF(checkriding,""),
BUILDIN_DEF2(savepoint,"save","sii"),
BUILDIN_DEF(savepoint,"sii"),
@@ -15063,7 +15190,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(openstorage,""),
BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi"),
- BUILDIN_DEF(produce,"i"),
+ BUILDIN_DEF(produce,"i?"),
BUILDIN_DEF(cooking,"i"),
BUILDIN_DEF(monster,"siisii?"),
BUILDIN_DEF(getmobdrops,"i"),
@@ -15310,6 +15437,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(pushpc,"ii"),
BUILDIN_DEF(buyingstore,"i"),
BUILDIN_DEF(searchstores,"ii"),
+ BUILDIN_DEF(successruneuse,"?"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
diff --git a/src/map/skill.c b/src/map/skill.c
index 976f50bd4..26d812d86 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -311,7 +311,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill
// Calculate base heal rate
hp = ( ( ( status_get_lv(src) + status_get_int(src) ) / 5) * 30 ) * skill / 10;
- // Increment skill and status based modifiers
+ // Increment heal by skill/type modifiers
if( sd && ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0) )
mod += skill * 2;
else if( src->type == BL_HOM && (skill = merc_hom_checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 )
@@ -319,7 +319,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill
break;
}
- // Increment skill and status based modifiers
+ // Increment heal by item-based modifiers
if( sd && (skill = pc_skillheal_bonus(sd, skill_id)) )
mod += skill;
if( tsd && (skill = pc_skillheal2_bonus(tsd, skill_id)) )
@@ -332,8 +332,8 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill
mod -= sc->data[SC_CRITICALWOUND]->val2;
if( sc->data[SC_INCHEALRATE] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN )
mod += sc->data[SC_INCHEALRATE]->val1; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish]
-// if( sc->data[SC_VITALITYACTIVATION] && heal && skill_id != BA_APPLEIDUN )
-// mod += sc->data[SC_VITALITYACTIVATION]->val2;
+ if( sc->data[SC_VITALITYACTIVATION] && heal && skill_id != BA_APPLEIDUN )
+ mod += sc->data[SC_VITALITYACTIVATION]->val2;
}
// Adjust the HP recovered rate by adding all of the modifiers together.
@@ -981,9 +981,19 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
case NPC_CRITICALWOUND:
sc_start(bl,SC_CRITICALWOUND,100,skilllv,skill_get_time2(skillid,skilllv));
break;
+ case RK_WINDCUTTER:
+ sc_start(bl,SC_FEAR,3+2*skilllv,skilllv,skill_get_time(skillid,skilllv));
+ break;
+ case RK_DRAGONBREATH:
+ sc_start4(bl,SC_BURNING,15,skilllv,src->id,0,0,skill_get_time(skillid,skilllv));
+ break;
case AB_ADORAMUS:
- sc_start(bl, SC_BLIND, 100, skilllv, skill_get_time(skillid, skilllv));
- sc_start(bl, SC_ADORAMUS, 100, skilllv, skill_get_time2(skillid, skilllv));
+ if ( sd )
+ {
+ int rate = (skilllv*4) + sd->status.job_level / 2;
+ sc_start(bl, SC_BLIND, rate, skilllv, skill_get_time(skillid, skilllv));
+ sc_start(bl, SC_ADORAMUS, rate, skilllv, skill_get_time2(skillid, skilllv));
+ }
break;
}
@@ -1734,8 +1744,19 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if( damage > 0 && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) )
&& skillid != WS_CARTTERMINATION )
- rdamage = battle_calc_return_damage(bl, damage, dmg.flag);
-
+ {
+ if( sc && sc->data[SC_DEATHBOUND] && !is_boss(bl) && map_check_dir(map_calc_dir(src,bl->x,bl->y),unit_getdir(bl)))
+ {
+ int skilllv = sc->data[SC_DEATHBOUND]->val1;
+ clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1);
+ rdamage = damage * ((500 + 100*skilllv) / 100);
+ damage = rdamage * 70 / 100;
+ skill_blown(src, src, skill_get_blewcount(skillid,skilllv), unit_getdir(src), 0);
+ status_change_end(dsrc,SC_DEATHBOUND,INVALID_TIMER);
+ }
+ else
+ rdamage = battle_calc_return_damage(bl, damage, dmg.flag);
+ }
//Skill hit type
type=(skillid==0)?5:skill_get_hit(skillid);
@@ -1851,6 +1872,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case NPC_CRITICALSLASH:
case TF_DOUBLE:
case GS_CHAINACTION:
+ case RK_DEATHBOUND:
dmg.dmotion = clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2);
break;
@@ -1994,6 +2016,9 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
skill_additional_effect(bl, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
}
+ if( damage > 0 && skillid == RK_CRUSHSTRIKE )
+ skill_break_equip(src,EQP_WEAPON,2000,BCT_SELF);
+
if (!(flag&2) &&
(
skillid == MG_COLDBOLT || skillid == MG_FIREBOLT || skillid == MG_LIGHTNINGBOLT
@@ -2402,6 +2427,16 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
}
}
break;
+ case RK_HUNDREDSPEAR:
+ if(src->type == BL_PC)
+ {
+ int skill_lv = pc_checkskill((struct map_session_data *)src,KN_SPEARBOOMERANG);
+ if(skill_lv > 0)
+ skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,skill_lv,tick,skl->flag);
+ }
+ else
+ skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,1,tick,skl->flag);
+ break;
default:
skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
break;
@@ -2625,6 +2660,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_BLEEDING:
case NPC_CRITICALWOUND:
case NPC_HELLPOWER:
+ case RK_SONICWAVE:
+ case RK_WINDCUTTER:
case AB_DUPLELIGHT_MELEE:
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -3068,6 +3105,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_SMOKING:
case GS_FLING:
case NJ_ZENYNAGE:
+ case RK_DRAGONBREATH:
skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -3124,6 +3162,18 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
status_change_end(src, SC_HIDING, INVALID_TIMER);
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
break;
+
+ case RK_HUNDREDSPEAR:
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if(rand()%100 < (10 + 3*skilllv)) {
+ skill_blown(src,bl,6,-1,0);
+ skill_addtimerskill(src,tick+800,bl->id,0,0,skillid,skilllv,BF_WEAPON,flag);
+ }
+ break;
+ case RK_CRUSHSTRIKE:
+ if( sd )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
case 0:
if(sd) {
if (flag & 3){
@@ -3371,9 +3421,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AL_DECAGI:
case MER_DECAGI:
- if (skilllv >= battle_config.max_decagi_lv)
+ if (skilllv = battle_config.max_decagi_lv)
clif_skill_nodamage (src, bl, skillid, skilllv,
- sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), (battle_config.max_decagi - 2), (battle_config.max_decagi_dur * 100)));
+ sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), (battle_config.max_decagi - 2), battle_config.max_decagi_dur));
else
clif_skill_nodamage (src, bl, skillid, skilllv,
sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), skilllv, skill_get_time(skillid,skilllv)));
@@ -3729,6 +3779,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ST_PRESERVE:
case NPC_INVINCIBLE:
case NPC_INVINCIBLEOFF:
+ case RK_DEATHBOUND:
+ case RK_MILLENNIUMSHIELD:
+ case RK_CRUSHSTRIKE:
+ case RK_GIANTGROWTH:
+ case RK_STONEHARDSKIN:
+ case RK_VITALITYACTIVATION:
+ case RK_ABUNDANCE:
case AB_RENOVATIO:
case AB_EXPIATIO:
case AB_DUPLELIGHT:
@@ -4099,6 +4156,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case BS_ADRENALINE2:
case BS_WEAPONPERFECT:
case BS_OVERTHRUST:
+ case RK_FIGHTINGSPIRIT: //Splash range in skill_db is 0, should be map-wide according to party_foreachsamemap
if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) {
clif_skill_nodamage(bl,bl,skillid,skilllv,
sc_start2(bl,type,100,skilllv,(src == bl)? 1:0,skill_get_time(skillid,skilllv)));
@@ -5743,6 +5801,74 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_skill_nodamage(src, bl, skillid, skilllv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS));
}
break;
+ case RK_ENCHANTBLADE:
+ i = status_get_int(src) + status_get_lv(src) / 10;
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(bl,type,100,i,skill_get_time(skillid,skilllv)));
+ break;
+ case RK_IGNITIONBREAK:
+ if(flag&1)
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else
+ {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub, bl,
+ skill_get_splash(skillid, skilllv),BL_CHAR,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+ case RK_DRAGONHOWLING:
+ if(flag&1)
+ sc_start(bl,SC_FEAR,50 + skilllv * 6,skilllv,skill_get_time2(skillid,skilllv));
+ else
+ {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub, bl,
+ skill_get_splash(skillid, skilllv),BL_CHAR,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+ case RK_REFRESH:
+ {
+ int heal = sstatus->max_hp * 25 / 100;
+ status_heal(bl,heal,0,0);
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
+ status_change_clear_buffs(bl,6);
+ }
+ break;
+ case RK_STORMBLAST:
+ if( flag&1 )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else
+ {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub, bl,
+ skill_get_splash(skillid, skilllv),BL_CHAR,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+ case RK_PHANTOMTHRUST:
+ if(battle_check_target(src,bl,BCT_ENEMY) > 0 || battle_check_target(src,bl,BCT_PARTY) > 0)
+ {
+ if(!map[bl->m].flag.gvg && !map[bl->m].flag.battleground && !(status_get_mode(bl)&MD_BOSS))
+ {
+ int x = 0, y = 0;
+ if(bl->x > src->x) x = 1;
+ else if(bl->x < src->x) x = -1;
+ if(bl->y >= src->y) y = 1;
+ else if(bl->y < src->y) y = -1;
+ unit_movepos(bl, src->x+x, src->y+y, 1, 0);
+ clif_slide(bl,src->x+x, src->y+y);
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if (battle_check_target(src,bl,BCT_ENEMY) > 0 )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ break;
case AB_ANCILLA:
if(sd) {
if (skill_produce_mix(sd, skillid, 12333, 0, 0, 0, 1))
@@ -5774,6 +5900,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
int heal = skill_calc_heal(src, bl, AL_HEAL, lv, true);
if( status_isimmune(bl) )
heal = 0;
+
+ if( sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 )
+ heal += ((heal / 100) * (i * 10) / 4);
+
clif_skill_nodamage(bl, bl, skillid, heal, 1);
status_heal(bl, heal, 0, 0);
}
@@ -5786,15 +5916,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
{
if( dstsd && dstsd->special_state.no_magic_damage )
break;
- clif_skill_nodamage(bl, bl, skillid, skilllv,
- sc_start4(bl, type, 100, skilllv, 0, 0, 1, skill_get_time(skillid, skilllv)));
+
+ if ( sd && sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 0)
+ {
+ clif_skill_nodamage(bl, bl, skillid, skilllv,
+ sc_start4(bl, type, 100, skilllv, 0, 0, i, skill_get_time(skillid, skilllv)));
+ }
}
else
party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
break;
case AB_ORATIO:
if (flag&1)
- sc_start(bl, type, 40+skilllv*5, skilllv, skill_get_time(skillid, skilllv));
+ sc_start(bl, type, 40+5*skilllv, skilllv, skill_get_time(skillid, skilllv));
else
{
clif_skill_nodamage(src, bl, skillid, skilllv, 1);
@@ -5808,30 +5942,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AB_LAUDARAMUS:
if( (flag&1) || sd == NULL || sd->status.party_id == 0 )
{
- if( tsc && (rand()%100 < 30+5*skilllv) )
+ if( tsc && (rand()%100 < 40+10*skilllv) )
{
switch(skillid)
{
case AB_LAUDAAGNUS:
- if( tsc->data[SC_STONE] || tsc->data[SC_FREEZE] || tsc->data[SC_BLIND] )
+ if( tsc->data[SC_STONE] || tsc->data[SC_FREEZE] || tsc->data[SC_BLIND] ) //TODO: Freezing, Crystallization and Burning
{
status_change_end(bl, SC_STONE, INVALID_TIMER);
status_change_end(bl, SC_FREEZE, INVALID_TIMER);
status_change_end(bl, SC_BLIND, INVALID_TIMER);
}
+ else
+ clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
break;
case AB_LAUDARAMUS:
- if( tsc->data[SC_STUN] || tsc->data[SC_SLEEP] || tsc->data[SC_SILENCE] )
+ if( tsc->data[SC_STUN] || tsc->data[SC_SLEEP] || tsc->data[SC_SILENCE] ) // TODO: Howling of Mandragora, and Deep Sleep
{
status_change_end(bl, SC_STUN, INVALID_TIMER);
status_change_end(bl, SC_SLEEP, INVALID_TIMER);
status_change_end(bl, SC_SILENCE, INVALID_TIMER);
}
+ else
+ clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
break;
}
}
- clif_skill_nodamage(bl, bl, skillid, skilllv,
- sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
}
else if( sd )
party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv),
@@ -5839,7 +5975,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;
case AB_CLEARANCE:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- if( rand()%100 >= 50+10*skilllv )
+ if( rand()%100 >= 60+10*skilllv )
{
if (sd)
clif_skill_fail(sd,skillid,0,0);
@@ -5903,7 +6039,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN:
case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE:
case SC_SERVICE4U: case SC_PARTYFLEE: /*case SC_ANGEL_PROTECT:*/
- case SC_EPICLESIS:
+ case SC_EPICLESIS: case SC_DEATHBOUND: case SC_FIGHTINGSPIRIT:
+ case SC_ABUNDANCE: case SC_MILLENNIUMSHIELD:
// not implemented
//case SC_BUCHEDENOEL: case SC_POPECOOKIE:
//case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ:
@@ -6801,6 +6938,23 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
}
break;
+ case RK_WINDCUTTER:
+ i = skill_get_splash(skillid, skilllv);
+ clif_skill_damage(src, src, tick, 0, 0, -1, 1, skillid, -1, 0);
+ map_foreachinarea(skill_area_sub,
+ src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL),
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ break;
+
+ case RK_DRAGONBREATH:
+ i = skill_get_splash(skillid, skilllv);
+ map_foreachinarea(skill_area_sub,
+ src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL),
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
+ skill_castend_damage_id);
+ break;
+
case AB_EPICLESIS:
if( skill_unitsetting(src, skillid, skilllv, x, y, 0) )
{
@@ -6862,7 +7016,8 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
sd->sc.data[SC_DANCING] ||
sd->sc.data[SC_BERSERK] ||
sd->sc.data[SC_BASILICA] ||
- sd->sc.data[SC_MARIONETTE]
+ sd->sc.data[SC_MARIONETTE] ||
+ sd->sc.data[SC_DEATHBOUND]
)) {
skill_failed(sd);
return 0;
@@ -8960,13 +9115,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
clif_skill_fail(sd,skill,0,0);
return 0;
break;
-/*
case ST_DRAGON:
if(!pc_isdragon(sd)) {
clif_skill_fail(sd,skill,25,0);
return 0;
}
break;
+/*
case ST_WARG:
if(!pc_iswarg(sd)) {
clif_skill_fail(sd,skill,0,0);
@@ -11274,12 +11429,32 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
}
}
+ if(skill_id == RK_RUNEMASTERY)
+ { // Now we figure out how many runes we're going to make. :3
+ int skill_lv = pc_checkskill(sd,skill_id);
+ if( skill_lv > 4 && skill_lv < 10) // level 5~9 can make 1~2 runes
+ qty=(rand()%2)+1;
+ else if( skill_lv == 10 ) // Level 10 can make 1~3 runes
+ qty=(rand()%3)+1;
+
+ // Check to see if the amount of runes will exceed 20.
+ i = pc_search_inventory(sd,nameid);
+ if( i >= 0 && sd->status.inventory[i].amount+qty > 20 ) // Cancel creation if created stones will exceed 20.
+ {
+ clif_msg(sd,0x61b);
+ return 0;
+ }
+ }
+
for(i=0;i<MAX_PRODUCE_RESOURCE;i++){
int j,id,x;
if( (id=skill_produce_db[idx].mat_id[i]) <= 0 )
continue;
num++;
- x=qty*skill_produce_db[idx].mat_amount[i];
+ if (skill_id == RK_RUNEMASTERY)
+ x=skill_produce_db[idx].mat_amount[i]; // RK_RUNEMASTERY only uses one set of required items, even if making more than 1 item
+ else
+ x=qty*skill_produce_db[idx].mat_amount[i];
do{
int y=0;
j = pc_search_inventory(sd,id);
@@ -11372,8 +11547,57 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
make_per = make_per * battle_config.pp_rate / 100;
break;
case SA_CREATECON: // Elemental Converter Creation
+ case AB_ANCILLA: // Ancilla Creation
make_per = 100000; // should be 100% success rate
break;
+ case RK_RUNEMASTERY: //Information from iROWiki and RuneItemInfo.lua
+ {
+ int skill_lv = pc_checkskill(sd,skill_id);
+
+ make_per = 5100 + 20 * skill_lv; // Base chance.
+
+ //Take stats into account before applying non-modified values.
+ make_per += (status->dex / 30 + status->luk / 10) + sd->status.job_level / 10 * 100;
+
+ switch(sd->produce_itemusedid)
+ { // Add success rate based on what type of stone is used.
+ case 12737:
+ make_per += 200; break;
+ case 12734:
+ make_per += 500; break;
+ case 12738:
+ make_per += 800; break;
+ case 12735:
+ make_per += 1100; break;
+ case 12736:
+ make_per += 1400; break;
+ default:
+ break;
+ }
+ sd->produce_itemusedid = 0;
+
+ switch(nameid)
+ { // Reduce success rate based on what rank stone we're making.
+ case 12727: // Runstone_Verkana
+ make_per -= 2000; // S Class
+ break;
+ case 12725: // Runstone_Nosiege
+ case 12730: // Runstone_Urj
+ make_per -= 1500; // A Rank
+ break;
+ case 12728: // Runstone_Isia
+ case 12732: // Runstone_Pertz
+ make_per -= 1000; // B Rank
+ break;
+ case 12726: // Runstone_Rhydo
+ case 12729: // Runstone_Asir
+ case 12731: // Runstone_Turisus
+ case 12733: // Runstone_Hagalas
+ make_per -= 500; // C Rank
+ break;
+ }
+ break;
+ }
default:
if (sd->menuskill_id == AM_PHARMACY &&
sd->menuskill_val > 10 && sd->menuskill_val <= 20)
@@ -11412,7 +11636,6 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
if(make_per < 1) make_per = 1;
-
if(rand()%10000 < make_per || qty > 1){ //Success, or crafting multiple items.
struct item tmp_item;
memset(&tmp_item,0,sizeof(tmp_item));
@@ -11512,6 +11735,7 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
case AM_TWILIGHT2:
case AM_TWILIGHT3:
case ASC_CDP:
+ case RK_RUNEMASTERY:
clif_produceeffect(sd,2,nameid);
clif_misceffect(&sd->bl,5);
break;
@@ -11565,6 +11789,10 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
clif_produceeffect(sd,1,nameid);
clif_misceffect(&sd->bl,2);
break;
+ case RK_RUNEMASTERY:
+ clif_produceeffect(sd,3,nameid);
+ clif_misceffect(&sd->bl,6);
+ break;
default:
if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 )
{ //Cooking items.
diff --git a/src/map/status.c b/src/map/status.c
index cf3d17228..f704ee0d6 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -413,6 +413,17 @@ void initChangeTables(void)
add_sc( SA_ELEMENTGROUND , SC_ELEMENTALCHANGE );
add_sc( SA_ELEMENTWIND , SC_ELEMENTALCHANGE );
+ set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE );
+ set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE );
+ set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE );
+ set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE );
+ set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE );
+ set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR );
+ set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_DEF2|SCB_MDEF2 );
+ set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION , SI_VITALITYACTIVATION , SCB_REGEN );
+ set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_ASPD );
+ set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE );
+
set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED );
add_sc( AB_CLEMENTIA , SC_BLESSING );
add_sc( AB_CANTO , SC_INCREASEAGI );
@@ -503,7 +514,7 @@ void initChangeTables(void)
StatusIconChangeTable[SC_SPL_DEF] = SI_SPL_DEF;
StatusIconChangeTable[SC_MANU_MATK] = SI_MANU_MATK;
StatusIconChangeTable[SC_SPL_MATK] = SI_SPL_MATK;
- //StatusIconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY; // Causes client to crash when mousing over state icon?
+
//Cash Items
StatusIconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH;
StatusIconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH;
@@ -575,7 +586,7 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL;
StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED;
StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL;
- //StatusChangeFlagTable[SC_MOVHASTE_INFINITY] = SCB_SPEED;
+ StatusChangeFlagTable[SC_FEAR] |= SCB_HIT|SCB_FLEE;
// Cash Items
StatusChangeFlagTable[SC_FOOD_STR_CASH] = SCB_STR;
@@ -906,6 +917,9 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
}
if(sp) {
+ if (sc && sc->data[SC_BERSERK] && sc->data[SC_ABUNDANCE]) // SP does not regenerate during Frenzy.
+ sp = 0;
+
if((unsigned int)sp > status->max_sp - status->sp)
sp = status->max_sp - status->sp;
}
@@ -1758,7 +1772,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
sd->regen.state.block = 0;
- sd->fixedcastrate=0;
+ sd->fixedcastrate=100;
sd->weapon_matk = 0;
sd->equipment_matk = 0;
@@ -1804,7 +1818,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK);
status->size = (sd->class_&JOBL_BABY)?0:1;
- if (battle_config.character_size && pc_isriding(sd)) { //[Lupus]
+ if (battle_config.character_size && (pc_isriding(sd) || pc_isdragon(sd))) { //[Lupus]
if (sd->class_&JOBL_BABY) {
if (battle_config.character_size&2)
status->size++;
@@ -2089,7 +2103,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->left_weapon.atkmods[1] = atkmods[1][sd->weapontype2];
sd->left_weapon.atkmods[2] = atkmods[2][sd->weapontype2];
- if(pc_isriding(sd) &&
+ if((pc_isriding(sd) || pc_isdragon(sd)) &&
(sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR))
{ //When Riding with spear, damage modifier to mid-class becomes
//same as versus large size.
@@ -2348,7 +2362,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
status->aspd_rate -= ((skill+1)/2) * 10;
if(pc_isriding(sd))
status->aspd_rate += 500-100*pc_checkskill(sd,KN_CAVALIERMASTERY);
-
+ if(pc_isdragon(sd))
+ status->aspd_rate += 750-75*pc_checkskill(sd,RK_DRAGONTRAINING); // Officiak is rumoured to be 75+5*skilllv...giving you 125% ASPD?
status->adelay = 2*status->amotion;
@@ -2366,6 +2381,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->max_weight += 2000*skill;
if(pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0)
sd->max_weight += 10000;
+ if(pc_isdragon(sd) && (skill=pc_checkskill(sd,RK_DRAGONTRAINING))>0)
+ sd->max_weight += 5000+2000*skill; //+200 weight per level of RK_DRAGINTRAINING
if(sc->data[SC_KNOWLEDGE])
sd->max_weight += sd->max_weight*sc->data[SC_KNOWLEDGE]->val1/10;
if((skill=pc_checkskill(sd,ALL_INCCARRY))>0)
@@ -2775,6 +2792,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
} else
regen->flag&=~sce->val4; //Remove regen as specified by val4
}
+ if( sc->data[SC_VITALITYACTIVATION] )
+ regen->flag &=~RGN_SP;
}
/// Recalculates parts of an object's battle status according to the specified flags.
@@ -3324,6 +3343,8 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang
str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF;
if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && str < 50)
str = 50;
+ if(sc->data[SC_GIANTGROWTH])
+ str += 30;
return (unsigned short)cap_value(str,0,USHRT_MAX);
}
@@ -3658,6 +3679,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change
hit += 20; // RockmanEXE; changed based on updated [Reddozen]
if(sc->data[SC_MERC_HITUP])
hit += sc->data[SC_MERC_HITUP]->val2;
+ if(sc->data[SC_FEAR])
+ hit -= hit * 20/100;
return (short)cap_value(hit,1,SHRT_MAX);
}
@@ -3707,6 +3730,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
flee += sc->data[SC_PARTYFLEE]->val1 * 10;
if(sc->data[SC_MERC_FLEEUP])
flee += sc->data[SC_MERC_FLEEUP]->val2;
+ if(sc->data[SC_FEAR])
+ flee -= flee * 20/100;
return (short)cap_value(flee,1,SHRT_MAX);
}
@@ -3795,6 +3820,8 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change
+ def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100;
if(sc->data[SC_FLING])
def2 -= def2 * (sc->data[SC_FLING]->val3)/100;
+ if (sc->data[SC_STONEHARDSKIN])
+ def2 += sc->data[SC_STONEHARDSKIN]->val3;
return (short)cap_value(def2,1,SHRT_MAX);
}
@@ -3835,6 +3862,8 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang
return 0;
if(sc->data[SC_MINDBREAKER])
mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100;
+ if (sc->data[SC_STONEHARDSKIN])
+ mdef2 += sc->data[SC_STONEHARDSKIN]->val3;
return (short)cap_value(mdef2,1,SHRT_MAX);
}
@@ -3864,6 +3893,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
else
if( sd && pc_isriding(sd) )
val = 25;
+ if( sd && pc_isdragon(sd) )
+ val = 25;
speed_rate -= val;
}
@@ -3946,8 +3977,6 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
val = max( val, 10 * sc->data[SC_AVOID]->val1 );
if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
val = max( val, 75 );
- //if( sc->data[SC_MOVHASTE_INFINITY] )
- // val = max( val, 25 );
//FIXME: official items use a single bonus for this [ultramage]
if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup
@@ -4078,6 +4107,9 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE )
aspd_rate += 100;
}
+ if(sc->data[SC_FIGHTINGSPIRIT])
+ aspd_rate -= sc->data[SC_FIGHTINGSPIRIT]->val3;
+
return (short)cap_value(aspd_rate,0,SHRT_MAX);
}
@@ -4857,6 +4889,34 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if( !sc )
return 0; //Unable to receive status changes
+ if( sc->data[SC_REFRESH] )
+ {
+ if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX && type != SC_STUN ) // Immune to all common status ailments except stun (iROWiki)
+ return 0;
+ switch( type )
+ {
+ case SC_FEAR:
+ case SC_BURNING:
+ // Not implemented yet. (kRO 3-x balance update)
+ //case SC_POISONINGWEAPON:
+ //case SC_TOXIN:
+ //case SC_PARALYSE:
+ //case SC_VENOMBLEED:
+ //case SC_MAGICMUSHROOM:
+ //case SC_DEATHHURT:
+ //case SC_PYREXIA:
+ //case SC_OBLIVIONCURSE:
+ //case SC_LEECHESEND:
+ //case SC_FROSTMISTY:
+ //case SC_MARSHOFABYSS:
+ //case SC_DEEP_SLEEP:
+ //case SC_COLD:
+ //case SC_FREEZE_SP:
+ //case SC_MANDRAGORA:
+ return 0;
+ }
+ }
+
if( status_isdead(bl) )
return 0;
@@ -4887,6 +4947,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
return 0;
case SC_SLEEP:
case SC_STUN:
+ case SC_BURNING:
if (sc->opt1)
return 0; //Cannot override other opt1 status changes. [Skotlex]
break;
@@ -5251,6 +5312,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_FOOD_LUK_CASH:
status_change_end(bl, SC_LUKFOOD, INVALID_TIMER);
break;
+ case SC_FIGHTINGSPIRIT:
+ if (sc->data[SC_FIGHTINGSPIRIT])
+ status_change_end(bl, SC_FIGHTINGSPIRIT, INVALID_TIMER);
+ break;
}
//Check for overlapping fails
@@ -5290,6 +5355,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_MARIONETTE2:
case SC_NOCHAT:
case SC_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation.
+ case SC_FEAR:
+ case SC_BURNING:
return 0;
case SC_COMBO:
case SC_DANCING:
@@ -5399,12 +5466,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
break;
case SC_KYRIE:
val2 = status->max_hp * (val1 * 2 + 10) / 100; //%Max HP to absorb
- // val4 determines if status is casued by Kyrie or Praefatio,
- // as Praefatio blocks more hits than Kyrie Elesion.
- if( !val4 ) //== PR_KYRIE
+ // val4 holds current about of party memebers when casting AB_PRAEFATIO,
+ // as Praefatio's barrier has more health and blocks more hits than Kyrie Elesion.
+ if( val4 < 1 ) //== PR_KYRIE
val3 = (val1 / 2 + 5);
- else //== AB_PRAEFATIO
+ else
+ { //== AB_PRAEFATIO
+ val2 += val4 * 2; //Increase barrier strength per party member.
val3 = 6 + val1;
+ }
if( sd )
val1 = min(val1,pc_checkskill(sd,PR_KYRIE)); // use skill level to determine barrier health.
break;
@@ -6143,6 +6213,34 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_KAIZEL:
val2 = 10*val1; //% of life to be revived with
break;
+ case SC_MILLENNIUMSHIELD:
+ val2 = (rand()%100<20) ? 4 : ((rand()%100<30) ? 3 : ((rand()%100<50) ? 2 : 0)); // 20% for 4, 30% for 3, 50% for 2
+ val3 = 1000; // Initial Sheild health. (Additional sheilds health are set in battle.c when shield is broken.)
+ if( sd && val2 > 0)
+ clif_millenniumshield(sd,val2);
+ break;
+ case SC_STONEHARDSKIN:
+ val2 = (status->hp * 20 / 100);
+ if( val2 > 0 )
+ status_heal(bl, -val2, 0, 0); // Reduce health by 20%
+ if ( sd )
+ val3 = (sd->status.job_level * pc_checkskill(sd,RK_RUNEMASTERY)) / 4;
+ break;
+ case SC_VITALITYACTIVATION:
+ val2 = 50; // Increase HP recovery effects by 50%
+ val3 = 50; // Reduce SP recovery effects by 50%
+ break;
+ case SC_FIGHTINGSPIRIT: // attack is handled in battle.c
+ //val2 holds the source of the skill (1 = caster, 0 = party member.)
+ //official ASPD bonus appears to be (Rune Mastery Level / 10 x 4).
+ val3 = 10 * (sd?pc_checkskill(sd,RK_RUNEMASTERY):1); //Kind of dirty means to implement 4aspd increase.
+ break;
+ case SC_ABUNDANCE:
+ val3 = tick / 10000;
+ if(val3 < 1)
+ val3 = 1;
+ tick = 10000;
+ break;
case SC_EPICLESIS:
val2 = 5 * val1; // % HP gained * level of Epiclesis cast.
break;
@@ -6161,13 +6259,24 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
val2 = 5*val1; // DEF reduced by 5*Skill Level percent.
break;
case SC_DUPLELIGHT:
- val2 = 10+val1*2; //Chance of MELEE proc
- val3 = 10+val1*2; //Chance of MAGIC proc
+ val2 = 10+2*val1; //Chance of MELEE proc
+ val3 = 10+2*val1; //Chance of MAGIC proc
break;
case SC_AB_SECRAMENT:
val2 = 10*val1; //Fixed cast time reduced by 10*Skill Level
break;
+ case SC_FEAR:
+ if (tick < 2000)
+ val3 = 2000;
+ else
+ val3 = tick - 2000;
+ tick = 2000;
+ break;
+ case SC_BURNING:
+ val4 = tick/2000;
+ tick = 3000;
+ break;
// case SC_ARMOR_ELEMENT:
// case SC_ARMOR_RESIST:
// Mod your resistance against elements:
@@ -6232,6 +6341,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_STUN:
case SC_SLEEP:
case SC_STONE:
+ case SC_BURNING:
if (sd && pc_issit(sd)) //Avoid sprite sync problems.
pc_setstand(sd);
case SC_TRICKDEAD:
@@ -6246,6 +6356,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_CLOSECONFINE2:
case SC_ANKLE:
case SC_SPIDERWEB:
+ case SC_FEAR:
unit_stop_walking(bl,1);
break;
case SC_HIDING:
@@ -6265,10 +6376,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
switch(type)
{
//OPT1
- case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
- case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
- case SC_STUN: sc->opt1 = OPT1_STUN; break;
- case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break;
+ case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
+ case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
+ case SC_STUN: sc->opt1 = OPT1_STUN; break;
+ case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break;
+ case SC_BURNING: sc->opt1 = OPT1_BURNING; break;
//OPT2
case SC_POISON: sc->opt2 |= OPT2_POISON; break;
case SC_CURSE: sc->opt2 |= OPT2_CURSE; break;
@@ -6278,6 +6390,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break;
case SC_BLEEDING: sc->opt2 |= OPT2_BLEEDING; break;
case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break;
+ case SC_FEAR: sc->opt2 |= OPT2_FEAR; break;
//OPT3
case SC_TWOHANDQUICKEN:
case SC_ONEHAND:
@@ -6612,7 +6725,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
return 0;
if (tid == INVALID_TIMER) {
- if( (type == SC_ENDURE /*|| type == SC_MOVHASTE_INFINITY*/ ) && sce->val4 )
+ if( (type == SC_ENDURE) && sce->val4 )
//Do not end infinite endure or speed adjustment.
return 0;
if (sce->timer != INVALID_TIMER) //Could be a SC with infinite duration
@@ -6943,6 +7056,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
status_change_end(tbl, SC_STOP, INVALID_TIMER);
}
break;
+ case SC_MILLENNIUMSHIELD:
+ if ( sd )
+ clif_millenniumshield(sd,0);
+ break;
}
opt_flag = 1;
@@ -6951,6 +7068,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_FREEZE:
case SC_STUN:
case SC_SLEEP:
+ case SC_BURNING:
sc->opt1 = 0;
break;
@@ -6966,6 +7084,9 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_SIGNUMCRUCIS:
sc->opt2 &= ~OPT2_SIGNUMCRUCIS;
break;
+ case SC_FEAR:
+ sc->opt2 &= ~OPT2_FEAR;
+ break;
case SC_HIDING:
sc->option &= ~OPTION_HIDE;
@@ -7495,8 +7616,24 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
return 0;
}
break;
+ case SC_ABUNDANCE:
+ if((--sce->val3) > 0)
+ {
+ int sp = 60;
+ if(sd) {
+ if( sd->status.sp < sd->status.max_sp )
+ {
+ if( sd->status.sp + sp > sd->status.max_sp ) //No overhealing SP.
+ sp = sd->status.max_sp - sd->status.sp;
+ clif_heal(sd->fd,SP_SP,sp);
+ status_heal(bl, 0, sp, 0);
+ }
+ }
+ sc_timer_next(10000+tick, status_change_timer, bl->id, data);
+ }
+ break;
case SC_RENOVATIO:
- if((--sc->data[type]->val2) > 0) {
+ if((--sce->val2) > 0) {
int heal = status->max_hp * 3 / 100;
if( status->hp + heal > status->max_hp )
heal = status->max_hp - status->hp;
@@ -7509,6 +7646,31 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
return 0;
}
break;
+ case SC_FEAR:
+ if(sce->val3 > 0)
+ {
+ sc_timer_next(sce->val3+tick, status_change_timer, bl->id, data);
+ sce->val3 = 0;
+ }
+ break;
+ case SC_BURNING:
+ if(--(sce->val4) >= 0)
+ {
+ int flag, hp = 0;
+ struct block_list *src = map_id2bl(sce->val2);
+
+ hp = 1000+(status->max_hp*3 /100);
+ map_freeblock_lock();
+ clif_damage(bl,bl,tick,status->amotion,0,hp,1,9,0);
+ status_damage(src, bl, hp, 0, 0, 1);
+
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if(!flag)
+ sc_timer_next( 3000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
}
// default for all non-handled control paths is to end the status
@@ -7569,7 +7731,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap)
/*==========================================
* Clears buffs/debuffs of a character.
- * type&1 -> buffs, type&2 -> debuffs
+ * type&1 -> buffs, type&2 -> debuffs, type&4 -> sc_refresh
*------------------------------------------*/
int status_change_clear_buffs (struct block_list* bl, int type)
{
@@ -7628,6 +7790,13 @@ int status_change_clear_buffs (struct block_list* bl, int type)
case SC_EXPBOOST:
case SC_JEXPBOOST:
case SC_ITEMBOOST:
+ case SC_GIANTGROWTH:
+ case SC_REFRESH:
+ case SC_STONEHARDSKIN:
+ case SC_VITALITYACTIVATION:
+ case SC_FIGHTINGSPIRIT:
+ case SC_ABUNDANCE:
+ case SC_MILLENNIUMSHIELD:
continue;
//Debuffs that can be removed.
@@ -7644,9 +7813,33 @@ int status_change_clear_buffs (struct block_list* bl, int type)
case SC_STRIPSHIELD:
case SC_STRIPARMOR:
case SC_STRIPHELM:
+ //Cannot be removed by Refresh.
+ if (type&4)
+ continue;
case SC_ADORAMUS:
if (!(type&2))
continue;
+
+ //Debuffs that can be removed by Refresh..
+ case SC_FEAR:
+ case SC_BURNING:
+ //case SC_POISONINGWEAPON:
+ //case SC_TOXIN:
+ //case SC_PARALYSE:
+ //case SC_VENOMBLEED:
+ //case SC_MAGICMUSHROOM:
+ //case SC_DEATHHURT:
+ //case SC_PYREXIA:
+ //case SC_OBLIVIONCURSE:
+ //case SC_LEECHESEND:
+ //case SC_FROSTMISTY:
+ //case SC_MARSHOFABYSS:
+ //case SC_DEEP_SLEEP:
+ //case SC_COLD:
+ //case SC_FREEZE_SP:
+ //case SC_MANDRAGORA:
+ if (!(type&4))
+ continue;
break;
//The rest are buffs that can be removed.
case SC_BERSERK:
diff --git a/src/map/status.h b/src/map/status.h
index 27c3e1782..033e7ca38 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -330,11 +330,21 @@ typedef enum sc_type {
SC_FOOD_DEX_CASH,
SC_FOOD_INT_CASH,
SC_FOOD_LUK_CASH,
- //SC_MOVHASTE_INFINITY,
- SC_PARTYFLEE = 310,
- //SC_ENDURE_MDEF, //311
-
+ SC_PARTYFLEE,
+
// Third Jobs - Maintaining SI order for SCs.
+ SC_FEAR, // 310,
+ SC_BURNING,
+ SC_ENCHANTBLADE,
+ SC_DEATHBOUND,
+ SC_REFRESH,
+ SC_GIANTGROWTH, //315
+ SC_STONEHARDSKIN,
+ SC_VITALITYACTIVATION,
+ SC_FIGHTINGSPIRIT,
+ SC_ABUNDANCE,
+ SC_MILLENNIUMSHIELD, // 320
+ //
SC_EPICLESIS = 325,
SC_ORATIO,
SC_LAUDAAGNUS,
@@ -344,7 +354,11 @@ typedef enum sc_type {
SC_DUPLELIGHT,
SC_ADORAMUS = 380,
SC_AB_SECRAMENT = 451,
+
+// SC_ALL_RIDING = 472,
+ SC_CRUSHSTRIKE = 599,
+
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
} sc_type;
@@ -666,8 +680,7 @@ enum si_type {
SI_CASH_PLUSONLYJOBEXP = 312,
SI_PARTYFLEE = 313,
// SI_ANGEL_PROTECT = 314,
-/*
- SI_ENDURE_MDEF = 315,
+// SI_ENDURE_MDEF = 315,
SI_ENCHANTBLADE = 316,
SI_DEATHBOUND = 317,
SI_REFRESH = 318,
@@ -676,12 +689,11 @@ enum si_type {
SI_VITALITYACTIVATION = 321,
SI_FIGHTINGSPIRIT = 322,
SI_ABUNDANCE = 323,
- SI_REUSE_MILLENNIUMSHIELD = 324,
- SI_REUSE_CRUSHSTRIKE = 325,
- SI_REUSE_REFRESH = 326,
- SI_REUSE_STORMBLAST = 327,
- SI_VENOMIMPRESS = 328,
-*/
+// SI_REUSE_MILLENNIUMSHIELD = 324,
+// SI_REUSE_CRUSHSTRIKE = 325,
+// SI_REUSE_REFRESH = 326,
+// SI_REUSE_STORMBLAST = 327,
+// SI_VENOMIMPRESS = 328,
SI_EPICLESIS = 329,
SI_ORATIO = 330,
SI_LAUDAAGNUS = 331,
@@ -973,7 +985,9 @@ enum si_type {
SI_BEER_BOTTLE_CAP = 617,
SI_OVERLAPEXPUP = 618,
SI_PC_IZ_DUN05 = 619,
+*/
SI_CRUSHSTRIKE = 620,
+/*
SI_MONSTER_TRANSFORM = 621,
SI_SIT = 622,
SI_ONAIR = 623,
@@ -1111,6 +1125,7 @@ enum {
OPTION_DRAGON3 = 0x01000000,
OPTION_DRAGON4 = 0x02000000,
OPTION_DRAGON5 = 0x04000000,
+ OPTION_ALL_RIDING= 0x08000000,
// compound constants
OPTION_CART = OPTION_CART1|OPTION_CART2|OPTION_CART3|OPTION_CART4|OPTION_CART5,
OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5,
diff --git a/src/map/unit.c b/src/map/unit.c
index c8b0e0d26..b51e2602d 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -837,6 +837,8 @@ int unit_can_move(struct block_list *bl)
sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1))
|| sc->data[SC_MADNESSCANCEL]
|| (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF)
+ || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val3 > 0)
+ || sc->data[SC_DEATHBOUND]
))
return 0;
}