Explorar o código

* 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://svn.code.sf.net/p/rathena/svn/branches/renewal@14983 54d463be-8e91-2dee-dedb-b68131a5f0ec

L0neW0lf.eAthena %!s(int64=13) %!d(string=hai) anos
pai
achega
f6b46546b1
Modificáronse 18 ficheiros con 1029 adicións e 115 borrados
  1. 13 0
      Changelog-Renewal.txt
  2. 8 0
      conf/battle/items.conf
  3. 1 1
      src/char/char.c
  4. 1 1
      src/char_sql/char.c
  5. 4 2
      src/map/atcommand.c
  6. 176 28
      src/map/battle.c
  7. 2 0
      src/map/battle.h
  8. 57 16
      src/map/clif.c
  9. 3 0
      src/map/clif.h
  10. 54 0
      src/map/map.c
  11. 1 1
      src/map/mob.c
  12. 77 5
      src/map/pc.c
  13. 6 1
      src/map/pc.h
  14. 131 3
      src/map/script.c
  15. 252 24
      src/map/skill.c
  16. 214 21
      src/map/status.c
  17. 27 12
      src/map/status.h
  18. 2 0
      src/map/unit.c

+ 13 - 0
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

+ 8 - 0
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

+ 1 - 1
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;

+ 1 - 1
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;

+ 4 - 2
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;

+ 176 - 28
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,              },
 };
 
 

+ 2 - 0
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);

+ 57 - 16
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,

+ 3 - 0
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_ */

+ 54 - 0
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);
 		}
 	}
 	

+ 1 - 1
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;

+ 77 - 5
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;
+}
+
+
 /*==========================================
  * アイテムを使う
  *------------------------------------------*/
@@ -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.
@@ -6926,6 +6982,22 @@ int pc_setriding(TBL_PC* sd, int flag)
 	return 0;
 }
 
+/*==========================================
+ * 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;
+}
 /*==========================================
  * アイテムドロップ可不可判定
  *------------------------------------------*/

+ 6 - 1
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);

+ 131 - 3
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,""),

+ 252 - 24
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.

+ 214 - 21
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:

+ 27 - 12
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,

+ 2 - 0
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;
 	}