Explorar o código

Fixed bugreport:6324 where re-spawning mob still hits/chases its previous attacker.
Partial fixed bugreport:6396 where Chemical Protection skills doesn't check targets current equipments.
Finally added almost all Kagerou/Oboro skills only one more left..phew...:D
(KG_KAGEHUMI,KG_KYOMU,KG_KAGEMUSYA,OB_ZANGETSU,OB_OBOROGENSOU,OB_OBOROGENSOU_TRANSITION_ATK,OB_AKAITSUKI)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@16560 54d463be-8e91-2dee-dedb-b68131a5f0ec

rud0lp20 %!s(int64=12) %!d(string=hai) anos
pai
achega
df8a3313ef

+ 12 - 0
db/pre-re/skill_cast_db.txt

@@ -1681,6 +1681,18 @@
 3021,500,0,0,5000,0,0,0
 //-- KO_IZAYOI
 3022,0,0,0,30000:45000:60000:75000:90000,0,60000,0
+//-- KG_KAGEHUMI
+3023,0,0,0,5000,0,5000,0
+//-- KG_KYOMU
+3024,0,0,0,10000:15000:20000:25000:30000,0,0,0
+//-- KG_KAGEMUSYA
+3025,0,0,0,60000:90000:120000:15000:180000,0,0,0
+//-- OB_ZANGETSU
+3026,0,0,0,60000:90000:120000:15000:180000,0,0,0
+//-- OB_OBOROGENSOU
+3027,0,0,0,10000:15000:20000:25000:30000,0,0,0
+//-- OB_AKAITSUKI
+3029,0,0,0,10000:15000:20000:25000:30000,0,0,0
 //==========================================
 
 //===== Homunculus Skills ==================

+ 7 - 0
db/pre-re/skill_db.txt

@@ -1031,6 +1031,13 @@
 3020,7,6,2,0,0,0,1,3,yes,0,0,0,magic,0,		KO_ZENKAI,Zenkai
 3021,5:6:7:8:9,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	KO_GENWAKU,Genwaku
 3022,0,6,4,0,0x1,0,5,0,no,0,0,0,none,0,		KO_IZAYOI,Izayoi
+3023,0,6,4,0,0x3,2:3:4:5:6,5,0,no,0,0,0,none,0,	KG_KAGEHUMI,Kagehumi
+3024,7,6,1,0,0x1,0,5,1,no,0,0,0,none,0,		KG_KYOMU,Kyomu
+3025,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	KG_KAGEMUSYA,Kagemusha
+3026,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	OB_ZANGETSU,Zangetsu
+3027,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	OB_OBOROGENSOU,Oboro Gensou
+3028,1,6,4,0,0x2,3,1,1,no,0,0,0,weapon,0,	OB_OBOROGENSOU_TRANSITION_ATK,
+3029,7,6,1,0,0x1,0,5,0,no,0,0,0,none,0,		OB_AKAITSUKI,Akaitsuki
 
 8001,9,6,4,0,0x1,0,5,1,no,0,0,0,magic,0,	HLIF_HEAL,Healing Touch
 8002,0,6,4,0,0x3,-1,5,1,no,0,0,0,none,0,	HLIF_AVOID,Avoid

+ 6 - 0
db/pre-re/skill_require_db.txt

@@ -807,6 +807,12 @@
 3020,0,0,30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_ZENKAI#Zenkai#
 3021,0,0,40:44:48:52:56,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_GENWAKU#Genwaku#
 3022,0,0,70:75:80:85:90,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_IZAYOI#Izayoi#
+3023,0,0,60:65:70:75:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KAGEHUMI#Kagehumi#
+3024,0,0,50,0,0,0,99,0,0,none,0,7524,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KYOMU#Kyomu#
+3025,0,0,25:30:35:40:45,0,0,0,99,0,0,none,0,6499,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KAGEMUSYA#Kagemusha#
+3026,0,0,60:70:80:90:100 ,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_ZANGETSU#Zangetsu#
+3027,0,0,55:60:65:70:75 ,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_OBOROGENSOU#Oboro Gensou#
+3029,0,0,20:30:40:50:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_AKAITSUKI#Akaitsuki#
 
 10010,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//GD_BATTLEORDER##
 10011,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//GD_REGENERATION##

+ 12 - 0
db/re/skill_cast_db.txt

@@ -1681,6 +1681,18 @@
 3021,500,0,0,5000,0,0,0
 //-- KO_IZAYOI
 3022,0,0,0,30000:45000:60000:75000:90000,0,60000,0
+//-- KG_KAGEHUMI
+3023,0,0,0,5000,0,5000,0
+//-- KG_KYOMU
+3024,0,0,0,10000:15000:20000:25000:30000,0,0,0
+//-- KG_KAGEMUSYA
+3025,0,0,0,60000:90000:120000:15000:180000,0,0,0
+//-- OB_ZANGETSU
+3026,0,0,0,60000:90000:120000:15000:180000,0,0,0
+//-- OB_OBOROGENSOU
+3027,0,0,0,10000:15000:20000:25000:30000,0,0,0
+//-- OB_AKAITSUKI
+3029,0,0,0,10000:15000:20000:25000:30000,0,0,0
 //==========================================
 
 //===== Homunculus Skills ==================

+ 7 - 0
db/re/skill_db.txt

@@ -1032,6 +1032,13 @@
 3020,7,6,2,0,0,0,1,3,yes,0,0,0,magic,0,		KO_ZENKAI,Zenkai
 3021,5:6:7:8:9,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	KO_GENWAKU,Genwaku
 3022,0,6,4,0,0x1,0,5,0,no,0,0,0,none,0,		KO_IZAYOI,Izayoi
+3023,0,6,4,0,0x3,2:3:4:5:6,5,0,no,0,0,0,none,0,	KG_KAGEHUMI,Kagehumi
+3024,7,6,1,0,0x1,0,5,1,no,0,0,0,none,0,		KG_KYOMU,Kyomu
+3025,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	KG_KAGEMUSYA,Kagemusha
+3026,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	OB_ZANGETSU,Zangetsu
+3027,7,6,16,0,0x1,0,5,1,no,0,0,0,none,0,	OB_OBOROGENSOU,Oboro Gensou
+3028,1,6,4,0,0x2,3,1,1,no,0,0,0,weapon,0,	OB_OBOROGENSOU_TRANSITION_ATK,
+3029,7,6,1,0,0x1,0,5,0,no,0,0,0,none,0,		OB_AKAITSUKI,Akaitsuki
 
 8001,9,6,4,0,0x1,0,5,1,no,0,0,0,magic,0,	HLIF_HEAL,Healing Touch
 8002,0,6,4,0,0x3,-1,5,1,no,0,0,0,none,0,	HLIF_AVOID,Avoid

+ 6 - 0
db/re/skill_require_db.txt

@@ -809,6 +809,12 @@
 3020,0,0,30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_ZENKAI#Zenkai#
 3021,0,0,40:44:48:52:56,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_GENWAKU#Genwaku#
 3022,0,0,70:75:80:85:90,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KO_IZAYOI#Izayoi#
+3023,0,0,60:65:70:75:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KAGEHUMI#Kagehumi#
+3024,0,0,50,0,0,0,99,0,0,none,0,7524,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KYOMU#Kyomu#
+3025,0,0,25:30:35:40:45,0,0,0,99,0,0,none,0,6499,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//KG_KAGEMUSYA#Kagemusha#
+3026,0,0,60:70:80:90:100 ,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_ZANGETSU#Zangetsu#
+3027,0,0,55:60:65:70:75 ,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_OBOROGENSOU#Oboro Gensou#
+3029,0,0,20:30:40:50:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//OB_AKAITSUKI#Akaitsuki#
 
 10010,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//GD_BATTLEORDER##
 10011,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	//GD_REGENERATION##

+ 7 - 2
src/map/battle.c

@@ -1456,9 +1456,10 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 
 	if( sd && !skill_num ) {	//Check for double attack.
 		if( ( ( skill_lv = pc_checkskill(sd,TF_DOUBLE) ) > 0 && sd->weapontype1 == W_DAGGER )
-			|| ( sd->bonus.double_rate > 0 && sd->weapontype1 != W_FIST ) ) //Will fail bare-handed 
+			|| ( sd->bonus.double_rate > 0 && sd->weapontype1 != W_FIST ) //Will fail bare-handed 
+			|| ( sc && sc->data[SC_KAGEMUSYA] && sd->weapontype1 != W_FIST )) // Need confirmation
 		{	//Success chance is not added, the higher one is used [Skotlex]
-			if( rnd()%100 < ( 5*skill_lv > sd->bonus.double_rate ? 5*skill_lv : sd->bonus.double_rate ) )
+			if( rnd()%100 < ( 5*skill_lv > sd->bonus.double_rate ? 5*skill_lv : sc && sc->data[SC_KAGEMUSYA]?sc->data[SC_KAGEMUSYA]->val1*3:sd->bonus.double_rate ) )
 			{
 				wd.div_ = skill_get_num(TF_DOUBLE,skill_lv?skill_lv:1);
 				wd.type = 0x08;
@@ -4441,6 +4442,10 @@ int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int
 			if (rdamage < 1) rdamage = 1;
 		}
 	}
+
+	if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability
+		rdamage = 0;
+
 	return rdamage;
 }
 

+ 3 - 4
src/map/mob.c

@@ -959,6 +959,8 @@ int mob_spawn (struct mob_data *md)
 	md->attacked_id = 0;
 	md->target_id = 0;
 	md->move_fail_count = 0;
+	md->ud.state.attack_continue = 0;
+	md->ud.target_to = 0;
 	if( md->spawn_timer != INVALID_TIMER )
 	{
 		delete_timer(md->spawn_timer, mob_delayspawn);
@@ -2132,10 +2134,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 	if(src && src->type == BL_MOB)
 		mob_unlocktarget((struct mob_data *)src,tick);
-	
-	/* clear previous target otherwise we'll respawn aiming at the same dude */
-	md->attacked_id = 0;
-	
+		
 	if( sd ) {
 		if( sd->mission_mobid == md->class_) { //TK_MISSION [Skotlex]
 			if( ++sd->mission_count >= 100 && (temp = mob_get_random_id(0, 0xE, sd->status.base_level)) )

+ 1 - 0
src/map/pc.c

@@ -4120,6 +4120,7 @@ int pc_useitem(struct map_session_data *sd,int n)
 		sd->sc.data[SC_TRICKDEAD] ||
 		sd->sc.data[SC_HIDING] ||
 		sd->sc.data[SC__SHADOWFORM] ||
+		sd->sc.data[SC_KAGEHUMI] ||
 		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
 	))
 		return 0;

+ 132 - 49
src/map/skill.c

@@ -112,7 +112,7 @@ int firewall_unit_pos;
 int icewall_unit_pos;
 int earthstrain_unit_pos;
 //early declaration
-int skill_stasis_check(struct block_list *bl, int src_id, int skillid);
+int skill_block_check(struct block_list *bl, enum sc_type type, int skillid);
 static int skill_check_unit_range (struct block_list *bl, int x, int y, int skillid, int skilllv);
 static int skill_check_unit_range2 (struct block_list *bl, int x, int y, int skillid, int skilllv);
 static int skill_destroy_trap( struct block_list *bl, va_list ap );
@@ -2053,6 +2053,9 @@ static int skill_magic_reflect(struct block_list* src, struct block_list* bl, in
 	struct status_change *sc = status_get_sc(bl);
 	struct map_session_data* sd = BL_CAST(BL_PC, bl);
 
+	if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability
+		return  0;
+
 	// item-based reflection
 	if( sd && sd->bonus.magic_damage_return && type && rnd()%100 < sd->bonus.magic_damage_return )
 		return 1;
@@ -2208,6 +2211,15 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
 			|| (sc && sc->data[SC_REFLECTDAMAGE])) )
 		rdamage = battle_calc_return_damage(bl,src, &damage, dmg.flag, skillid);
 
+	if( damage && sc && sc->data[SC_GENSOU] && dmg.flag&BF_MAGIC ){
+		struct block_list *nbl = NULL;
+		nbl = battle_getenemyarea(bl,bl->x,bl->y,2,BL_CHAR,bl->id);
+		if( nbl ){ // Only one target is chosen.
+			damage = damage / 2; // Deflect half of the damage to a target nearby
+			clif_skill_damage(bl, nbl, tick, status_get_amotion(src), 0, status_fix_damage(bl,nbl,damage,0), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, 6);
+		}
+	}
+
 	//Skill hit type
 	type=(skillid==0)?5:skill_get_hit(skillid);
 
@@ -4701,8 +4713,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				if (tsc->data[SC_BERSERK])
 					heal = 0; //Needed so that it actually displays 0 when healing.
 			}
-			heal_get_jobexp = status_heal(bl,heal,0,0);
 			clif_skill_nodamage (src, bl, skillid, heal, 1);
+			if( tsc && tsc->data[SC_AKAITSUKI] && heal && skillid != HLIF_HEAL )
+				heal = ~heal + 1;
+			heal_get_jobexp = status_heal(bl,heal,0,0);
 
 			if(sd && dstsd && heal > 0 && sd != dstsd && battle_config.heal_exp > 0){
 				heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100;
@@ -6162,7 +6176,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	case AM_CP_ARMOR:
 	case AM_CP_HELM:
 		{
+			unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP};
 			enum sc_type scid = (sc_type)(SC_STRIPWEAPON + (skillid - AM_CP_WEAPON));
+
+			if( sd && ( bl->type != BL_PC || ( dstsd && pc_checkequip(dstsd,equip[skillid - AM_CP_WEAPON]) < 0 ) ) ){
+				clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
+				map_freeblock_unlock(); // Don't consume item requirements
+				return 0;
+			}
+
 			status_change_end(bl, scid, INVALID_TIMER);
 			clif_skill_nodamage(src,bl,skillid,skilllv,
 				sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
@@ -7511,8 +7533,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 				if( (dstsd && pc_ismadogear(dstsd)) || status_isimmune(bl) || (tsc && tsc->data[SC_BERSERK]))
 						i = 0; // Should heal by 0 or won't do anything?? in iRO it breaks the healing to members.. [malufett]
 
-				status_heal(bl, i, 0, 1);
 				clif_skill_nodamage(bl, bl, skillid, i, 1);
+				if( tsc && tsc->data[SC_AKAITSUKI] && i )
+					i = ~i + 1;
+				status_heal(bl, i, 0, 1);
 			}
 		}
 		else if( sd )
@@ -7648,7 +7672,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	 **/
 	case WL_STASIS:
 		if( flag&1 )
-			sc_start2(bl,type,100,skilllv,src->id,skill_get_time(skillid,skilllv));
+			sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv));
 		else
 		{
 			map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid, skilllv),BL_CHAR,src,skillid,skilllv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id);
@@ -8739,12 +8763,46 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		}
 		break;
 
+	case OB_AKAITSUKI:
+	case OB_OBOROGENSOU:
+		if( sd && ( (skillid == OB_OBOROGENSOU && bl->type == BL_MOB) // This skill does not work on monsters.
+			|| is_boss(bl) ) ){ // Does not work on Boss monsters.
+			clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
+			break;
+		}
 	case KO_IZAYOI:
+	case OB_ZANGETSU:
+	case KG_KYOMU:
+	case KG_KAGEMUSYA:
 		clif_skill_nodamage(src,bl,skillid,skilllv,
 			sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
 		clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
 		break;
 
+	case KG_KAGEHUMI:
+		if( flag&1 ){
+			if(tsc && ( tsc->option&(OPTION_CLOAK|OPTION_HIDE) || 
+				tsc->data[SC_CAMOUFLAGE] || tsc->data[SC__SHADOWFORM] ||
+				tsc->data[SC_MARIONETTE] || tsc->data[SC_HARMONIZE])){ 
+					sc_start(src, type, 100, skilllv, skill_get_time(skillid, skilllv));
+					sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv));
+					status_change_end(bl, SC_HIDING, INVALID_TIMER);
+					status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
+					status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
+					status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
+					status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER);
+					status_change_end(bl, SC_MARIONETTE, INVALID_TIMER);
+					status_change_end(bl, SC_HARMONIZE, INVALID_TIMER);
+			}
+			if( skill_area_temp[2] > 0){
+				clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+				sc_start(src, SC_STOP, 100, skilllv, skill_get_time(skillid, skilllv));
+			}
+		}else{
+			skill_area_temp[2] = 0;
+			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_nodamage_id);	
+		}
+		break;
 	default:
 		if( skillid >= HM_SKILLBASE && skillid <= HM_SKILLBASE + MAX_HOMUNSKILL ) {
 			if( src->type == BL_HOM && ((TBL_HOM*)src)->master->fd )
@@ -9982,7 +10040,8 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
 		sd->sc.data[SC_BASILICA] ||
 		sd->sc.data[SC_MARIONETTE] ||
 		sd->sc.data[SC_WHITEIMPRISON] ||
-		(sd->sc.data[SC_STASIS] && skill_stasis_check(&sd->bl, sd->sc.data[SC_STASIS]->val2, skill_num)) ||
+		(sd->sc.data[SC_STASIS] && skill_block_check(&sd->bl, SC_STASIS, skill_num)) ||
+		(sd->sc.data[SC_KAGEHUMI] && skill_block_check(&sd->bl, SC_KAGEHUMI, skill_num)) ||
 		sd->sc.data[SC_OBLIVIONCURSE] ||
 		sd->sc.data[SC__MANHOLE]
 	 )) {
@@ -10982,6 +11041,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
 				if( status_isimmune(bl) )
 					heal = 0;
 				clif_skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1);
+				if( tsc && tsc->data[SC_AKAITSUKI] && heal )
+					heal = ~heal + 1;
 				status_heal(bl, heal, 0, 0);
 				if( diff >= 500 )
 					sg->val1--;
@@ -11196,6 +11257,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
 			if( sg->src_id == bl->id && !(tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_BARDDANCER) )
 				break; // affects self only when soullinked
 			heal = skill_calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true);
+			if( tsc->data[SC_AKAITSUKI] && heal )
+				heal = ~heal + 1;
 			clif_skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1);
 			status_heal(bl, heal, 0, 0);
 			break;
@@ -11477,9 +11540,11 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
 				struct status_change *ssc = status_get_sc(ss);
 				if( ssc && ssc->data[SC_HEATER_OPTION] )
 					hp += hp * ssc->data[SC_HEATER_OPTION]->val3 / 100;
-				status_heal(bl, hp, 0, 0);
 				if( tstatus->hp != tstatus->max_hp )
 					clif_skill_nodamage(&src->bl, bl, AL_HEAL, hp, 0);
+				if( tsc && tsc->data[SC_AKAITSUKI] && hp )
+					hp = ~hp + 1;
+				status_heal(bl, hp, 0, 0);
 				sc_start(bl, SC_WARMER, 100, sg->skill_lv, skill_get_time2(sg->skill_id,sg->skill_lv));
 			}
 			break;
@@ -12589,6 +12654,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
 				return 0;
 			}
 			break;	
+		case LG_REFLECTDAMAGE:
+		case CR_REFLECTSHIELD:
+			if( sc && sc->data[SC_KYOMU] && rand()%100 < 30){
+				clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0);
+				return 0;
+			}
+			break;
 		case KO_KAHU_ENTEN:
 		case KO_HYOUHU_HUBUKI:
 		case KO_KAZEHU_SEIRAN:
@@ -16755,54 +16827,65 @@ void skill_init_unit_layout (void)
 	}
 
 }
-// Stasis skill usage check. [LimitLine/3CeAM]
-int skill_stasis_check(struct block_list *bl, int src_id, int skillid) {
+
+int skill_block_check(struct block_list *bl, sc_type type , int skillid) {
 	int inf = 0;
-	if( !bl || skillid < 1 )
-		return 0; // Can do it
-	inf = skill_get_inf2(skillid);
-	if( inf == INF2_SONG_DANCE || /*skill_get_inf2(skillid) == INF2_CHORUS_SKILL ||*/ inf == INF2_SPIRIT_SKILL )
-		return 1; // Can't do it.
+	struct status_change *sc = status_get_sc(bl); 
 
-	switch( skillid )
-	{
-		case NV_FIRSTAID:		case TF_HIDING:			case AS_CLOAKING:		case WZ_SIGHTRASHER:
-		case RG_STRIPWEAPON:		case RG_STRIPSHIELD:		case RG_STRIPARMOR:		case WZ_METEOR:
-		case RG_STRIPHELM:		case SC_STRIPACCESSARY:		case ST_FULLSTRIP:		case WZ_SIGHTBLASTER:
-		case ST_CHASEWALK:		case SC_ENERVATION:		case SC_GROOMY:			case WZ_ICEWALL:
-		case SC_IGNORANCE:		case SC_LAZINESS:		case SC_UNLUCKY:		case WZ_STORMGUST:
-		case SC_WEAKNESS:		case AL_RUWACH:			case AL_PNEUMA:			case WZ_JUPITEL:
-		case AL_HEAL:			case AL_BLESSING:		case AL_INCAGI:			case WZ_VERMILION:
-		case AL_TELEPORT:		case AL_WARP:			case AL_HOLYWATER:		case WZ_EARTHSPIKE:
-		case AL_HOLYLIGHT:		case PR_IMPOSITIO:		case PR_ASPERSIO:		case WZ_HEAVENDRIVE:
-		case PR_SANCTUARY:		case PR_STRECOVERY:		case PR_MAGNIFICAT:		case WZ_QUAGMIRE:
-		case ALL_RESURRECTION:		case PR_LEXDIVINA:		case PR_LEXAETERNA:		case HW_GRAVITATION:
-		case PR_MAGNUS:			case PR_TURNUNDEAD:		case MG_SRECOVERY:		case HW_MAGICPOWER:
-		case MG_SIGHT:			case MG_NAPALMBEAT:		case MG_SAFETYWALL:		case HW_GANBANTEIN:
-		case MG_SOULSTRIKE:		case MG_COLDBOLT:		case MG_FROSTDIVER:		case WL_DRAINLIFE:
-		case MG_STONECURSE:		case MG_FIREBALL:		case MG_FIREWALL:		case WL_SOULEXPANSION:
-		case MG_FIREBOLT:		case MG_LIGHTNINGBOLT:		case MG_THUNDERSTORM:		case MG_ENERGYCOAT:
-		case WL_WHITEIMPRISON:		case WL_SUMMONFB:		case WL_SUMMONBL:		case WL_SUMMONWB:
-		case WL_SUMMONSTONE:		case WL_SIENNAEXECRATE:		case WL_RELEASE:		case WL_EARTHSTRAIN:
-		case WL_RECOGNIZEDSPELL: 	case WL_READING_SB:		case SA_MAGICROD:		case SA_SPELLBREAKER:
-		case SA_DISPELL:		case SA_FLAMELAUNCHER:		case SA_FROSTWEAPON:		case SA_LIGHTNINGLOADER:
-		case SA_SEISMICWEAPON:		case SA_VOLCANO:		case SA_DELUGE:			case SA_VIOLENTGALE:
-		case SA_LANDPROTECTOR:		case PF_HPCONVERSION:		case PF_SOULCHANGE:		case PF_SPIDERWEB:
-		case PF_FOGWALL:		case TK_RUN:			case TK_HIGHJUMP:		case TK_SEVENWIND:
-		case SL_KAAHI:			case SL_KAUPE:			case SL_KAITE:
-
-		// Skills that need to be confirmed.
-		case SO_FIREWALK:		case SO_ELECTRICWALK:		case SO_SPELLFIST:		case SO_EARTHGRAVE:
-		case SO_DIAMONDDUST:		case SO_POISON_BUSTER:		case SO_PSYCHIC_WAVE:		case SO_CLOUD_KILL:
-		case SO_STRIKING:		case SO_WARMER:			case SO_VACUUM_EXTREME:		case SO_VARETYR_SPEAR:
-		case SO_ARRULLO:
-			return 1;	// Can't do it.
+	if( !sc || !bl || skillid < 1 )
+		return 0; // Can do it
 
-		default:
-			return 0; // Can do it.
+	switch(type){
+		case SC_STASIS:
+			inf = skill_get_inf2(skillid);
+			if( inf == INF2_SONG_DANCE || /*skill_get_inf2(skillid) == INF2_CHORUS_SKILL ||*/ inf == INF2_SPIRIT_SKILL )
+				return 1; // Can't do it.
+			switch( skillid )
+			{
+				case NV_FIRSTAID:		case TF_HIDING:			case AS_CLOAKING:		case WZ_SIGHTRASHER:
+				case RG_STRIPWEAPON:		case RG_STRIPSHIELD:		case RG_STRIPARMOR:		case WZ_METEOR:
+				case RG_STRIPHELM:		case SC_STRIPACCESSARY:		case ST_FULLSTRIP:		case WZ_SIGHTBLASTER:
+				case ST_CHASEWALK:		case SC_ENERVATION:		case SC_GROOMY:			case WZ_ICEWALL:
+				case SC_IGNORANCE:		case SC_LAZINESS:		case SC_UNLUCKY:		case WZ_STORMGUST:
+				case SC_WEAKNESS:		case AL_RUWACH:			case AL_PNEUMA:			case WZ_JUPITEL:
+				case AL_HEAL:			case AL_BLESSING:		case AL_INCAGI:			case WZ_VERMILION:
+				case AL_TELEPORT:		case AL_WARP:			case AL_HOLYWATER:		case WZ_EARTHSPIKE:
+				case AL_HOLYLIGHT:		case PR_IMPOSITIO:		case PR_ASPERSIO:		case WZ_HEAVENDRIVE:
+				case PR_SANCTUARY:		case PR_STRECOVERY:		case PR_MAGNIFICAT:		case WZ_QUAGMIRE:
+				case ALL_RESURRECTION:		case PR_LEXDIVINA:		case PR_LEXAETERNA:		case HW_GRAVITATION:
+				case PR_MAGNUS:			case PR_TURNUNDEAD:		case MG_SRECOVERY:		case HW_MAGICPOWER:
+				case MG_SIGHT:			case MG_NAPALMBEAT:		case MG_SAFETYWALL:		case HW_GANBANTEIN:
+				case MG_SOULSTRIKE:		case MG_COLDBOLT:		case MG_FROSTDIVER:		case WL_DRAINLIFE:
+				case MG_STONECURSE:		case MG_FIREBALL:		case MG_FIREWALL:		case WL_SOULEXPANSION:
+				case MG_FIREBOLT:		case MG_LIGHTNINGBOLT:		case MG_THUNDERSTORM:		case MG_ENERGYCOAT:
+				case WL_WHITEIMPRISON:		case WL_SUMMONFB:		case WL_SUMMONBL:		case WL_SUMMONWB:
+				case WL_SUMMONSTONE:		case WL_SIENNAEXECRATE:		case WL_RELEASE:		case WL_EARTHSTRAIN:
+				case WL_RECOGNIZEDSPELL: 	case WL_READING_SB:		case SA_MAGICROD:		case SA_SPELLBREAKER:
+				case SA_DISPELL:		case SA_FLAMELAUNCHER:		case SA_FROSTWEAPON:		case SA_LIGHTNINGLOADER:
+				case SA_SEISMICWEAPON:		case SA_VOLCANO:		case SA_DELUGE:			case SA_VIOLENTGALE:
+				case SA_LANDPROTECTOR:		case PF_HPCONVERSION:		case PF_SOULCHANGE:		case PF_SPIDERWEB:
+				case PF_FOGWALL:		case TK_RUN:			case TK_HIGHJUMP:		case TK_SEVENWIND:
+				case SL_KAAHI:			case SL_KAUPE:			case SL_KAITE:
+
+				// Skills that need to be confirmed.
+				case SO_FIREWALK:		case SO_ELECTRICWALK:		case SO_SPELLFIST:		case SO_EARTHGRAVE:
+				case SO_DIAMONDDUST:		case SO_POISON_BUSTER:		case SO_PSYCHIC_WAVE:		case SO_CLOUD_KILL:
+				case SO_STRIKING:		case SO_WARMER:			case SO_VACUUM_EXTREME:		case SO_VARETYR_SPEAR:
+				case SO_ARRULLO:
+					return 1;	// Can't do it.
+			}
+			break;
+		case SC_KAGEHUMI:
+			switch(skillid){
+				case TF_HIDING:		case AS_CLOAKING:	case GC_CLOAKINGEXCEED:	case SC_SHADOWFORM:
+				case MI_HARMONIZE:	case CG_MARIONETTE:	case AL_TELEPORT:		case TF_BACKSLIDING:
+				case RA_CAMOUFLAGE: case ST_CHASEWALK:	case GD_EMERGENCYCALL:
+					return 1; // needs more info
+			}
+			break;
 	}
 
-	return 0; // Can Cast anything else like Weapon Skills
+	return 0;
 }
 
 int skill_get_elemental_type( int skill_id , int skill_lv ) {

+ 1 - 1
src/map/skill.h

@@ -1788,7 +1788,7 @@ enum wl_spheres {
 	WLS_STONE,
 };
 int skill_spellbook (struct map_session_data *sd, int nameid);
-int skill_stasis_check(struct block_list *bl, int src_id, int skillid);
+int skill_block_check(struct block_list *bl, enum sc_type type, int skillid);
 /**
  * Guilottine Cross
  **/

+ 31 - 3
src/map/status.c

@@ -718,6 +718,12 @@ void initChangeTables(void) {
 	add_sc( KO_JYUSATSU			, SC_CURSE		  );
 	set_sc( KO_ZENKAI			, SC_ZENKAI				 , SI_ZENKAI			   , SCB_NONE );
 	set_sc( KO_IZAYOI			, SC_IZAYOI				 , SI_IZAYOI			   , SCB_MATK );
+	set_sc( KG_KYOMU			, SC_KYOMU				 , SI_KYOMU				   , SCB_NONE );
+	set_sc( KG_KAGEMUSYA		, SC_KAGEMUSYA			 , SI_KAGEMUSYA			   , SCB_NONE );
+	set_sc( KG_KAGEHUMI			, SC_KAGEHUMI			 , SI_KG_KAGEHUMI		   , SCB_NONE );
+	set_sc( OB_ZANGETSU			, SC_ZANGETSU			 , SI_ZANGETSU			   , SCB_MATK|SCB_BATK );
+	set_sc_with_vfx( OB_AKAITSUKI		, SC_AKAITSUKI			 , SI_AKAITSUKI			   , SCB_NONE );
+	set_sc( OB_OBOROGENSOU		, SC_GENSOU				 , SI_GENSOU			   , SCB_NONE );
 	
 	add_sc( MH_STAHL_HORN		 , SC_STUN            );
 	set_sc( MH_ANGRIFFS_MODUS	 , SC_ANGRIFFS_MODUS  , SI_ANGRIFFS_MODUS	, SCB_BATK|SCB_WATK|SCB_DEF|SCB_FLEE );
@@ -996,6 +1002,7 @@ void initChangeTables(void) {
 	StatusChangeStateTable[SC_NETHERWORLD]         |= SCS_NOMOVE;
 	StatusChangeStateTable[SC_CAMOUFLAGE]          |= SCS_NOMOVE|SCS_NOMOVECOND;
 	StatusChangeStateTable[SC_MEIKYOUSISUI]		   |= SCS_NOMOVE;
+	StatusChangeStateTable[SC_KAGEHUMI]            |= SCS_NOMOVE;
 		
 	/* StatusChangeState (SCS_) NOPICKUPITEMS */
 	StatusChangeStateTable[SC_HIDING]              |= SCS_NOPICKITEM;
@@ -1186,6 +1193,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 				status_change_end(target, SC_DANCING, INVALID_TIMER);
 			if(sc->data[SC_CLOAKINGEXCEED] && --(sc->data[SC_CLOAKINGEXCEED]->val2) <= 0)
 				status_change_end(target, SC_CLOAKINGEXCEED, INVALID_TIMER);
+			if(sc->data[SC_KAGEMUSYA] && --(sc->data[SC_KAGEMUSYA]->val3) <= 0)
+				status_change_end(target, SC_KAGEMUSYA, INVALID_TIMER);
 		}
 		unit_skillcastcancel(target, 2);
 	}
@@ -1611,7 +1620,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
 				sc->cant.cast ||
 				(sc->data[SC_MARIONETTE] && skill_num != CG_MARIONETTE) || //Only skill you can use is marionette again to cancel it
 				(sc->data[SC_MARIONETTE2] && skill_num == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another
-				(sc->data[SC_STASIS] && skill_stasis_check(src, sc->data[SC_STASIS]->val2, skill_num))
+				(sc->data[SC_STASIS] && skill_block_check(src, SC_STASIS, skill_num)) ||
+				(sc->data[SC_KAGEHUMI] && skill_block_check(src, SC_KAGEHUMI, skill_num))
 			))
 				return 0;
 
@@ -4381,7 +4391,9 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
 	// renewal EDP increases your base atk by atk x skill level
 	if( sc->data[SC_EDP] )
 		batk = batk * sc->data[SC_EDP]->val1;
-#endif
+#endif	
+	if( sc->data[SC_ZANGETSU] )
+		batk += batk * sc->data[SC_ZANGETSU]->val2 / 100;
 	return (unsigned short)cap_value(batk,0,USHRT_MAX);
 }
 
@@ -4506,6 +4518,8 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan
 		matk += 70;	
 	if(sc->data[SC_IZAYOI])
 		matk += 50 * sc->data[SC_IZAYOI]->val1;
+	if( sc->data[SC_ZANGETSU] )
+		matk += matk * sc->data[SC_ZANGETSU]->val2 / 100;
 
 	return (unsigned short)cap_value(matk,0,USHRT_MAX);
 }
@@ -8268,10 +8282,21 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
 			val2 = 2*val1 + rand()%val1;
 			clif_status_change(bl,SI_ACTIVE_MONSTER_TRANSFORM,1,0,1002,0,0); // Temporarily shows Poring need official [malufett]
 			break;
+		case SC_KAGEMUSYA:
+			val3 = val1 * 2;
 		case SC_IZAYOI:
 			val2 = tick/1000;
 			tick_time = 1000;
 			break;
+		case SC_ZANGETSU:
+			val2 = status_get_lv(bl) / 2 + 50;
+			break;
+		case SC_GENSOU:
+			if( rand()%100 < 50) // needs more info
+				status_zap(bl, 500, 500);
+			else
+				status_heal(bl, 500, 500, 0);
+			break;
 		default:
 			if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 )
 			{	//Status change with no calc, no icon, and no skill associated...? 
@@ -9880,7 +9905,10 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
 	case SC_RENOVATIO:
 		if( --(sce->val4) >= 0 )
 		{
-			status_heal(bl, status->max_hp * 3 / 100, 0, 2);
+			int heal = status->max_hp * 3 / 100;
+			if( sc && sc->data[SC_AKAITSUKI] && heal )
+				heal = ~heal + 1;
+			status_heal(bl, heal, 0, 2);
 			sc_timer_next(5000 + tick, status_change_timer, bl->id, data);
 			return 0;
 		}

+ 2 - 1
src/map/status.h

@@ -633,7 +633,8 @@ typedef enum sc_type {
 	SC_KYOMU,
 	SC_KAGEMUSYA,
 	SC_ZANGETSU,
-	SC_OBOROGENSOU,
+	SC_GENSOU,
+	SC_AKAITSUKI,
 
 	SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
 } sc_type;