浏览代码

Updated Flash Combo effect
* Includes fixes for Dragon Combo, Fallen Empire, Tiger Cannon, and Sky Net Blow.
* Removed the SR_FLASHCOMBO_ATK_STEP usage.
* Fixes #627, fixes #725, fixes #741, and fixes #765.
Thanks to @exneval and @Rytech!

aleos89 9 年之前
父节点
当前提交
fc6800701b
共有 10 个文件被更改,包括 172 次插入160 次删除
  1. 3 7
      db/pre-re/skill_db.txt
  2. 0 4
      db/pre-re/skill_require_db.txt
  3. 4 8
      db/re/skill_db.txt
  4. 0 4
      db/re/skill_require_db.txt
  5. 43 44
      src/map/battle.c
  6. 2 0
      src/map/battle.h
  7. 1 0
      src/map/map.h
  8. 119 88
      src/map/skill.c
  9. 0 4
      src/map/skill.h
  10. 0 1
      src/map/status.c

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

@@ -1099,11 +1099,11 @@
 
 //****
 // SR Sura
-2326,-2,8,1,-1,0,0,10,-2,no,0,0,0,weapon,0,0x0,	SR_DRAGONCOMBO,Dragon Combo
+2326,1,8,1,-1,0,0,10,-2,no,0,0,0,weapon,0,0x0,	SR_DRAGONCOMBO,Dragon Combo
 2327,0,8,4,-1,0x2,2,5,-3,no,0,0,0,weapon,3,0x0,	SR_SKYNETBLOW,Sky Net Blow
 2328,0,6,4,-1,0x2,1:2:3:4:5,5,1,no,0,0,0,weapon,0,0x0,	SR_EARTHSHAKER,Earth Shaker
-2329,-2,8,4,-1,0,0,5,-2,no,0,0x200,0,weapon,0,0x0,	SR_FALLENEMPIRE,Fallen Empire
-2330,-2,6,1,-1,0x42,1:1:1:1:1:2:2:2:2:2,10,1,yes,0,0,0,weapon,0,0x0,	SR_TIGERCANNON,Tiger Cannon
+2329,1,8,4,-1,0,0,5,-2,no,0,0x200,0,weapon,0,0x0,	SR_FALLENEMPIRE,Fallen Empire
+2330,1,6,1,-1,0x3,1:1:1:1:1:2:2:2:2:2,10,1,yes,0,0,0,weapon,0,0x0,	SR_TIGERCANNON,Tiger Cannon
 2331,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0,		SR_HELLGATE,Hell Gate
 2332,0,6,4,-1,0x2,3,5,1,no,0,0x40000,0,weapon,0,0x0,	SR_RAMPAGEBLASTER,Rampage Blaster
 2333,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0,		SR_CRESCENTELBOW,Crescent Elbow
@@ -1324,10 +1324,6 @@
 5012,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WL_TELEKINESIS_INTENSE,Intense Telekinesis
 5013,0,6,4,0,0x3,0,5,1,no,0,0,0,none,0,0x0, LG_KINGS_GRACE,King's Grace
 5014,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, ALL_FULL_THROTTLE,Full Throttle
-5015,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, SR_FLASHCOMBO_ATK_STEP1,Flash Combo Attack Step 1
-5016,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, SR_FLASHCOMBO_ATK_STEP2,Flash Combo Attack Step 2
-5017,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, SR_FLASHCOMBO_ATK_STEP3,Flash Combo Attack Step 3
-5018,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, SR_FLASHCOMBO_ATK_STEP4,Flash Combo Attack Step 4
 
 //****
 // Homunculus S

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

@@ -956,10 +956,6 @@
 5012,0,0,100:150:200:250:300,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,0,0			//WL_TELEKINESIS_INTENSE
 5013,0,0,200:180:160:140:120,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,0,0			//LG_KINGS_GRACE
 5014,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,0,0								//ALL_FULL_THROTTLE
-5015,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,0,0								//SR_FLASHCOMBO_ATK_STEP1 //All 4 steps are using temp req SP values for now.
-5016,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,0,0								//SR_FLASHCOMBO_ATK_STEP2
-5017,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,0,0								//SR_FLASHCOMBO_ATK_STEP3
-5018,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,0,0								//SR_FLASHCOMBO_ATK_STEP4
 
 // Copied Bard / Dancer Skills
 //3036,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,0,0							//BA_POEMBRAGI2

+ 4 - 8
db/re/skill_db.txt

@@ -1099,11 +1099,11 @@
 
 //****
 // SR Sura
-2326,-2,8,1,-1,0,0,10,-2,no,0,0,0,weapon,0,0x0,	SR_DRAGONCOMBO,Dragon Combo
+2326,1,8,1,-1,0,0,10,-2,no,0,0,0,weapon,0,0x0,	SR_DRAGONCOMBO,Dragon Combo
 2327,0,8,4,-1,0x2,2,5,-3,no,0,0,0,weapon,3,0x0,	SR_SKYNETBLOW,Sky Net Blow
 2328,0,6,4,-1,0x2,1:2:3:4:5,5,1,no,0,0,0,weapon,0,0x0,	SR_EARTHSHAKER,Earth Shaker
-2329,-2,8,4,-1,0,0,5,-2,no,0,0x200,0,weapon,0,0x0,	SR_FALLENEMPIRE,Fallen Empire
-2330,-2,6,1,-1,0x42,1:1:1:1:1:2:2:2:2:2,10,1,yes,0,0,0,weapon,0,0x0,	SR_TIGERCANNON,Tiger Cannon
+2329,1,8,4,-1,0,0,5,-2,no,0,0x200,0,weapon,0,0x0,	SR_FALLENEMPIRE,Fallen Empire
+2330,1,6,1,-1,0x3,1:1:1:1:1:2:2:2:2:2,10,1,yes,0,0,0,weapon,0,0x0,	SR_TIGERCANNON,Tiger Cannon
 2331,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0,		SR_HELLGATE,Hell Gate
 2332,0,6,4,-1,0x2,3,5,1,no,0,0x40000,0,weapon,0,0x0,	SR_RAMPAGEBLASTER,Rampage Blaster
 2333,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0,		SR_CRESCENTELBOW,Crescent Elbow
@@ -1119,7 +1119,7 @@
 2343,1:2:3:3:4:4:5:5:6:7,8,1,-1,0,0,10,-7,yes,0,0,0,weapon,0,0x0,	SR_GATEOFHELL,Gate of Hell
 2344,2,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0,	SR_GENTLETOUCH_QUIET,Gentle Touch - Quiet
 2345,2,6,16,0,0x1,0,5,1,no,0,0,0,none,0,0x0,	SR_GENTLETOUCH_CURE,Gentle Touch - Cure
-2346,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	SR_GENTLETOUCH_ENERGYGAIN,Gentle Touch - Energy Gain
+2346,2,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	SR_GENTLETOUCH_ENERGYGAIN,Gentle Touch - Energy Gain
 2347,2,6,16,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	SR_GENTLETOUCH_CHANGE,Gentle Touch - Change
 2348,2,6,16,0,0x1,0,5,1,yes,0,0,0,none,0,0x0,	SR_GENTLETOUCH_REVITALIZE,Gentle Touch - Revitalize
 //More from Sura but not following ID order
@@ -1327,10 +1327,6 @@
 5012,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, WL_TELEKINESIS_INTENSE,Intense Telekinesis
 5013,0,6,4,0,0x3,0,5,1,no,0,0,0,none,0,0x0, LG_KINGS_GRACE,King's Grace
 5014,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0,0x0, ALL_FULL_THROTTLE,Full Throttle
-5015,-2,8,1,-1,0,0,10,-2,no,0,0,0,weapon,0,0x0,                     	SR_FLASHCOMBO_ATK_STEP1,Flash Combo Attack Step 1
-5016,-2,8,4,-1,0,0,5,-2,no,0,0x200,0,weapon,0,0x0,                  	SR_FLASHCOMBO_ATK_STEP2,Flash Combo Attack Step 2
-5017,-2,6,1,-1,0x42,1:1:1:1:1:2:2:2:2:2,10,1,yes,0,0,0,weapon,0,0x0,	SR_FLASHCOMBO_ATK_STEP3,Flash Combo Attack Step 3
-5018,0,8,4,-1,0x2,2,5,-3,no,0,0,0,weapon,3,0x0,                     	SR_FLASHCOMBO_ATK_STEP4,Flash Combo Attack Step 4
 
 //****
 // Homunculus S

+ 0 - 4
db/re/skill_require_db.txt

@@ -971,10 +971,6 @@
 5012,0,0,100:150:200:250:300,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,0,0			//WL_TELEKINESIS_INTENSE
 5013,0,0,200:180:160:140:120,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,0,0			//LG_KINGS_GRACE
 5014,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,0,0								//ALL_FULL_THROTTLE
-5015,0,0,0,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,0,0								//SR_FLASHCOMBO_ATK_STEP1 //All 4 steps are using temp req SP values for now.
-5016,0,0,0,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,0,0								//SR_FLASHCOMBO_ATK_STEP2
-5017,0,0,0,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,0,0								//SR_FLASHCOMBO_ATK_STEP3
-5018,0,0,0,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,0,0								//SR_FLASHCOMBO_ATK_STEP4
 
 8001,0,0,13:16:19:22:25,0,0,0,99,0,0,none,0,0,545,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0				//HLIF_HEAL
 8002,0,0,20:25:30:35:40,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,0,0					//HLIF_AVOID

+ 43 - 44
src/map/battle.c

@@ -2765,6 +2765,7 @@ static struct Damage battle_calc_element_damage(struct Damage wd, struct block_l
 			switch( skill_id ) {
 				case MC_CARTREVOLUTION:
 				case SR_GATEOFHELL:
+				case SR_TIGERCANNON:
 				case KO_BAKURETSU:
 					//Forced to neutral element
 					wd.damage = battle_attr_fix(src, target, wd.damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
@@ -3941,38 +3942,30 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 			break;
 
 		case SR_DRAGONCOMBO:
-		case SR_FLASHCOMBO_ATK_STEP1:
 			skillratio += 40 * skill_lv;
 			RE_LVL_DMOD(100);
 			break;
 		case SR_FALLENEMPIRE:
-		case SR_FLASHCOMBO_ATK_STEP2:
 			// ATK [(Skill Level x 150 + 100) x Caster Base Level / 150] %
 			skillratio += 150 * skill_lv;
 			RE_LVL_DMOD(150);
  			break;
-		case SR_TIGERCANNON:
-		case SR_FLASHCOMBO_ATK_STEP3:
-			{
-				int hp = sstatus->max_hp * (10 + 2 * skill_lv) / 100, // skill_get_hp_rate(SR_TIGERCANNON, skill_lv)
-					sp = sstatus->max_sp * (5 + 1 * skill_lv) / 100; // skill_get_sp_rate(SR_TIGERCANNON, skill_lv)
-				if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE )
-					// Base_Damage = [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] %
-					skillratio += ((hp+sp) / 2);
-				else
-					// Base_Damage = [((Caster consumed HP + SP) / 4) x Caster Base Level / 100] %
-					skillratio += ((hp+sp) / 4);
+		case SR_TIGERCANNON: {
+				int hp = sstatus->max_hp * (10 + 2 * skill_lv) / 100,
+					sp = sstatus->max_sp * (5 + skill_lv) / 100;
+
+				if (wd.miscflag&4) // Base_Damage = [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] %
+					skillratio += -100 + (hp + sp) / 2;
+				else // Base_Damage = [((Caster consumed HP + SP) / 4) x Caster Base Level / 100] %
+					skillratio += -100 + (hp + sp) / 4;
 				RE_LVL_DMOD(100);
 			}
 			break;
 		case SR_SKYNETBLOW:
-		case SR_FLASHCOMBO_ATK_STEP4:
-			if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO )
-				//ATK [{(Skill Level x 100) + (Caster AGI) + 150} x Caster Base Level / 100] %
-				skillratio += (100 * skill_lv + sstatus->agi + 150);
-			else
-				//ATK [{(Skill Level x 80) + (Caster AGI)} x Caster Base Level / 100] %
-				skillratio += (80 * skill_lv + sstatus->agi);
+			if (wd.miscflag&4) // ATK [{(Skill Level x 100) + (Caster's AGI) + 150} x Caster's Base Level / 100] %
+				skillratio += 100 * skill_lv + sstatus->agi + 50;
+			else // ATK [{(Skill Level x 80) + (Caster's AGI)} x Caster's Base Level / 100] %
+				skillratio += -100 + 80 * skill_lv + sstatus->agi;
 			RE_LVL_DMOD(100);
 			break;
 
@@ -4283,22 +4276,13 @@ static int64 battle_calc_skill_constant_addition(struct Damage wd, struct block_
 				atk = damagevalue;
 			}
 			break;
-		case SR_TIGERCANNON:
-		case SR_FLASHCOMBO_ATK_STEP3:
-			// (Tiger Cannon skill level x 240) + (Target Base Level x 40)
-			if( skill_id == SR_FLASHCOMBO_ATK_STEP3 || (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) )
-				atk = ( skill_lv * 500 + status_get_lv(target) * 40 );
-			else
-				atk = ( skill_lv * 240 + status_get_lv(target) * 40 );
-			break;
 		case SR_FALLENEMPIRE:
-		case SR_FLASHCOMBO_ATK_STEP2:
 			// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)]
-			atk = ( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str);
-			if( tsd && tsd->weight )
-				atk += ( (tsd->weight/10) * sstatus->dex / 120 );
+			atk = ((tstatus->size + 1) * 2 + skill_lv - 1) * sstatus->str;
+			if (tsd && tsd->weight)
+				atk += tsd->weight / 10 * sstatus->dex / 120;
 			else
-				atk += ( status_get_lv(target) * 50 ); //mobs
+				atk += status_get_lv(target) * 50; //mobs
 			break;
 	}
 	return atk;
@@ -4446,14 +4430,12 @@ struct Damage battle_attack_sc_bonus(struct Damage wd, struct block_list *src, s
 					break;
 			}
 		}
-
 		if (sc->data[SC_FLASHCOMBO]) {
 			ATK_ADD(wd.damage, wd.damage2, sc->data[SC_FLASHCOMBO]->val2);
 #ifdef RENEWAL
 			ATK_ADD(wd.equipAtk, wd.equipAtk2, sc->data[SC_FLASHCOMBO]->val2);
 #endif
 		}
-
 		if((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) { // Monster Transformation bonus
 			if (sc->data[SC_MTF_RANGEATK]) {
 				ATK_ADDRATE(wd.damage, wd.damage2, sc->data[SC_MTF_RANGEATK]->val1);
@@ -5307,16 +5289,23 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 					ATK_ADD(wd.damage, wd.damage2, 10 * skill - i);
 			}
 			break;
+		case SR_TIGERCANNON:
+			if (wd.miscflag&4) {
+				ATK_ADD(wd.damage, wd.damage2, skill_lv * 500 + status_get_lv(target) * 40);
+			} else {
+				ATK_ADD(wd.damage, wd.damage2, skill_lv * 240 + status_get_lv(target) * 40);
+			}
+			break;
 		case SR_GATEOFHELL: {
-			struct status_data *sstatus = status_get_status_data(src);
+				struct status_data *sstatus = status_get_status_data(src);
 
-			ATK_ADD(wd.damage, wd.damage2, sstatus->max_hp - status_get_hp(src));
-			if(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) {
-				ATK_ADD(wd.damage, wd.damage2, (sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status_get_lv(src));
-			} else
-				ATK_ADD(wd.damage, wd.damage2, (sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status_get_lv(src));
-		}
-		break;
+				ATK_ADD(wd.damage, wd.damage2, sstatus->max_hp - status_get_hp(src));
+				if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) {
+					ATK_ADD(wd.damage, wd.damage2, sstatus->max_sp * (1 + skill_lv * 2 / 10) + 40 * status_get_lv(src));
+				} else
+					ATK_ADD(wd.damage, wd.damage2, sstatus->sp * (1 + skill_lv * 2 / 10) + 10 * status_get_lv(src));
+			}
+			break;
 	}
 
 	if(sd) {
@@ -5453,6 +5442,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 #endif
 		case SO_VARETYR_SPEAR:
 			return wd; //These skills will do a GVG fix later
+		case SR_TIGERCANNON:
+			if (wd.miscflag&8)
+				break; //Splash Tiger Cannon GVG fix will be calculated later [exneval]
 		default:
 			wd = battle_calc_attack_gvg_bg(wd, src, target, skill_id, skill_lv);
 			break;
@@ -5462,7 +5454,14 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 
 	battle_absorb_damage(target, &wd);
 
-	battle_do_reflect(BF_WEAPON,&wd, src, target, skill_id, skill_lv); //WIP [lighta]
+	switch(skill_id) { // Skill reflect gets calculated after all attack modifier
+		case SR_TIGERCANNON:
+			if (wd.miscflag&8)
+				break; //Splash Tiger Cannon will be reflected later [exneval]
+		default:
+			battle_do_reflect(BF_WEAPON, &wd, src, target, skill_id, skill_lv); //WIP [lighta]
+			break;
+	}
 
 	return wd;
 }

+ 2 - 0
src/map/battle.h

@@ -82,10 +82,12 @@ struct block_list;
 
 struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,uint16 skill_id,uint16 skill_lv,int flag);
 struct Damage battle_calc_attack_plant(struct Damage wd, struct block_list *src,struct block_list *target, uint16 skill_id, uint16 skill_lv);
+struct Damage battle_calc_attack_gvg_bg(struct Damage wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv);
 
 int64 battle_calc_return_damage(struct block_list *bl, struct block_list *src, int64 *, int flag, uint16 skill_id, bool status_reflect);
 
 void battle_drain(struct map_session_data *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int class_, bool infdef);
+void battle_do_reflect(int attack_type, struct Damage *wd, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv);
 
 int battle_attr_ratio(int atk_elem,int def_type, int def_lv);
 int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 damage,int atk_elem,int def_type, int def_lv);

+ 1 - 0
src/map/map.h

@@ -408,6 +408,7 @@ struct block_list {
 	int id;
 	int16 m,x,y;
 	enum bl_type type;
+	int64 damage;
 };
 
 

+ 119 - 88
src/map/skill.c

@@ -416,14 +416,6 @@ unsigned short skill_dummy2skill_id(unsigned short skill_id) {
 			return GN_HELLS_PLANT;
 		case GN_SLINGITEM_RANGEMELEEATK:
 			return GN_SLINGITEM;
-		case SR_FLASHCOMBO_ATK_STEP1:
-			return SR_DRAGONCOMBO;
-		case SR_FLASHCOMBO_ATK_STEP2:
-			return SR_FALLENEMPIRE;
-		case SR_FLASHCOMBO_ATK_STEP3:
-			return SR_TIGERCANNON;
-		case SR_FLASHCOMBO_ATK_STEP4:
-			return SR_SKYNETBLOW;
 		case RL_R_TRIP_PLUSATK:
 			return RL_R_TRIP;
 	}
@@ -1553,12 +1545,10 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 			skill_castend_damage_id(src,bl,LG_PINPOINTATTACK,rnd_value(1, pc_checkskill(sd,LG_PINPOINTATTACK)),tick,0);
 		break;
 	case SR_DRAGONCOMBO:
-	case SR_FLASHCOMBO_ATK_STEP1:
-		sc_start(src,bl, SC_STUN, 1 + skill_lv, skill_lv, skill_get_time(SR_DRAGONCOMBO, skill_lv));
+		sc_start(src,bl, SC_STUN, skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
 		break;
 	case SR_FALLENEMPIRE:
-	case SR_FLASHCOMBO_ATK_STEP2:
-		sc_start(src,bl, SC_STOP, 100, skill_lv, skill_get_time(SR_FALLENEMPIRE, skill_lv));
+		sc_start(src,bl, SC_STOP, 100, skill_lv, skill_get_time(skill_id, skill_lv));
 		break;
 	case SR_WINDMILL:
 		if( dstsd )
@@ -3124,17 +3114,36 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 
 	damage = dmg.damage + dmg.damage2;
 
-	if( (skill_id == AL_INCAGI || skill_id == AL_BLESSING ||
-		skill_id == CASH_BLESSING || skill_id == CASH_INCAGI ||
-		skill_id == MER_INCAGI || skill_id == MER_BLESSING) && tsd->sc.data[SC_CHANGEUNDEAD] )
-		damage = 1;
-
-	if (flag&8) {
-		skill_area_temp_i64[0] = damage;
-		if (is_infinite_defense(bl, dmg.flag)) {
-			dmg = battle_calc_attack_plant(dmg, src, bl, skill_id, skill_lv);
-			damage = dmg.damage + dmg.damage2;
-		}
+	switch(skill_id) {
+		case AL_INCAGI:
+		case CASH_INCAGI:
+		case MER_INCAGI:
+		case AL_BLESSING:
+		case CASH_BLESSING:
+		case MER_BLESSING:
+			if (tsc && tsc->data[SC_CHANGEUNDEAD])
+				damage = 1;
+			break;
+		case SR_TIGERCANNON:
+			if (skill_area_temp[1] == bl->id)
+				dsrc->damage = damage;
+			else {
+				dmg.damage = battle_attr_fix(src, bl, dsrc->damage, ELE_NEUTRAL, tstatus->def_ele, tstatus->ele_lv);
+				if (!dmg.damage) {
+					if (dmg.miscflag&4)
+						dmg.damage = skill_lv * 500 + status_get_lv(bl) * 40;
+					else
+						dmg.damage = skill_lv * 240 + status_get_lv(bl) * 40;
+				}
+				if (is_infinite_defense(bl, dmg.flag))
+					dmg = battle_calc_attack_plant(dmg, src, bl, skill_id, skill_lv);
+				else {
+					dmg = battle_calc_attack_gvg_bg(dmg, src, bl, skill_id, skill_lv);
+					battle_do_reflect(BF_WEAPON, &dmg, src, bl, skill_id, skill_lv);
+				}
+				damage = dmg.damage;
+			}
+			break;
 	}
 
 	if( damage && tsc && tsc->data[SC_GENSOU] && dmg.flag&BF_MAGIC ){
@@ -3263,6 +3272,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 		case KO_BAKURETSU:
 		case GN_CRAZYWEED_ATK:
 		case NC_MAGMA_ERUPTION:
+		case SR_TIGERCANNON:
 			dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,5);
 			break;
 		case GN_FIRE_EXPANSION_ACID:
@@ -3443,6 +3453,9 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 			case WM_METALICSOUND:
 				status_zap(bl, 0, damage*100/(100*(110-((sd) ? pc_checkskill(sd,WM_LESSON) : skill_get_max(WM_LESSON))*10)));
 				break;
+			case SR_TIGERCANNON:
+				status_zap(bl, 0, damage / 10); // 10% of damage dealt
+				break;
 		}
 		if( sd )
 			skill_onskillusage(sd, bl, skill_id, tick);
@@ -3846,14 +3859,17 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
 			break; // Source not on Map
 		if(skl->target_id) {
 			target = map_id2bl(skl->target_id);
-			if( ( skl->skill_id == RG_INTIMIDATE || skl->skill_id == SC_FATALMENACE ) && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) )
+			if ((skl->skill_id == RG_INTIMIDATE || skl->skill_id == SC_FATALMENACE) && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)))
 				target = src; //Required since it has to warp.
-			if(target == NULL)
-				break; // Target offline?
-			if(target->prev == NULL)
-				break; // Target not on Map
-			if(src->m != target->m)
-				break; // Different Maps
+			if (!target || target->prev == NULL || src->m != target->m) {
+				if (skl->skill_id == SR_SKYNETBLOW) {
+					clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skl->skill_id, skl->skill_lv, DMG_SKILL);
+					skill_area_temp[1] = 0;
+					map_foreachinrange(skill_area_sub, src, skill_get_splash(skl->skill_id, skl->skill_lv), splash_target(src), src,
+						skl->skill_id, skl->skill_lv, tick, skl->flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+				}
+				break; // Target offline, not on map, or in different maps
+			}
 			if(status_isdead(src)) {
 				switch(skl->skill_id) {
 					case WL_CHAINLIGHTNING_ATK:
@@ -3862,10 +3878,10 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
 					case WL_TETRAVORTEX_WIND:
 					case WL_TETRAVORTEX_GROUND:
 					// For SR_FLASHCOMBO
-					case SR_FLASHCOMBO_ATK_STEP1:
-					case SR_FLASHCOMBO_ATK_STEP2:
-					case SR_FLASHCOMBO_ATK_STEP3:
-					case SR_FLASHCOMBO_ATK_STEP4:
+					case SR_DRAGONCOMBO:
+					case SR_FALLENEMPIRE:
+					case SR_TIGERCANNON:
+					case SR_SKYNETBLOW:
 						break; // Exceptions
 					default:
 						continue; // Caster is Dead
@@ -4029,15 +4045,17 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
 						break;
 					}
 				// For SR_FLASHCOMBO
-				case SR_FLASHCOMBO_ATK_STEP1:
-				case SR_FLASHCOMBO_ATK_STEP2:
-				case SR_FLASHCOMBO_ATK_STEP3:
-				case SR_FLASHCOMBO_ATK_STEP4:
-					if( src->type == BL_PC ) {
-						const int use_skill_lv[] = { SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW };
-						if( distance_xy(src->x, src->y, target->x, target->y) >= 3 )
+				case SR_DRAGONCOMBO:
+				case SR_FALLENEMPIRE:
+				case SR_TIGERCANNON:
+				case SR_SKYNETBLOW:
+					if (src->type == BL_PC) {
+						if (distance_xy(src->x, src->y, target->x, target->y) >= 3)
 							break;
-						skill_castend_damage_id(src, target, skl->skill_id, pc_checkskill(((TBL_PC *)src), use_skill_lv[skl->skill_id-SR_FLASHCOMBO_ATK_STEP1]), tick, 0);
+						if (skl->skill_id == SR_TIGERCANNON)
+							skill_castend_nodamage_id(src, target, skl->skill_id, pc_checkskill(((TBL_PC *)src), skl->skill_id), tick, skl->flag);
+						else
+							skill_castend_damage_id(src, target, skl->skill_id, pc_checkskill(((TBL_PC *)src), skl->skill_id), tick, 0);
 					}
 					break;
 				case RL_SLUGSHOT:
@@ -4166,10 +4184,10 @@ int skill_cleartimerskill (struct block_list *src)
 				case WL_TETRAVORTEX_WIND:
 				case WL_TETRAVORTEX_GROUND:
 				// For SR_FLASHCOMBO
-				case SR_FLASHCOMBO_ATK_STEP1:
-				case SR_FLASHCOMBO_ATK_STEP2:
-				case SR_FLASHCOMBO_ATK_STEP3:
-				case SR_FLASHCOMBO_ATK_STEP4:
+				case SR_DRAGONCOMBO:
+				case SR_FALLENEMPIRE:
+				case SR_TIGERCANNON:
+				case SR_SKYNETBLOW:
 					continue;
 			}
 			delete_timer(ud->skilltimerskill[i]->timer, skill_timerskill);
@@ -4362,7 +4380,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case LG_OVERBRAND:
 	case LG_OVERBRAND_BRANDISH:
 	case SR_FALLENEMPIRE:
-	case SR_FLASHCOMBO_ATK_STEP2:
 	case SR_CRESCENTELBOW_AUTOSPELL:
 	case SR_GATEOFHELL:
 	case SR_GENTLETOUCH_QUIET:
@@ -4590,9 +4607,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 	case GC_COUNTERSLASH:
 	case LG_MOONSLASHER:
 	case LG_EARTHDRIVE:
+	case SR_TIGERCANNON:
 	case SR_RAMPAGEBLASTER:
 	case SR_SKYNETBLOW:
-	case SR_FLASHCOMBO_ATK_STEP4:
 	case SR_WINDMILL:
 	case SR_RIDEINLIGHTNING:
 	case WM_REVERBERATION_MELEE:
@@ -4624,6 +4641,17 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			if( skill_area_temp[1] != bl->id && !(skill_get_inf2(skill_id)&INF2_NPC_SKILL) )
 				sflag |= SD_ANIMATION; // original target gets no animation (as well as all NPC skills)
 
+			if (skill_area_temp[1] == bl->id && skill_id == SR_TIGERCANNON)
+				break; // Already done in 'skill_castend_nodamage_id' [exneval]
+			switch(skill_id) {
+				case SR_TIGERCANNON:
+					sflag |= 8;
+					// Fall through
+				case SR_SKYNETBLOW:
+					sflag |= flag&4;
+					break;
+				break;
+			}
 			heal = (int)skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag);
 			if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) {
 				clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1);
@@ -5357,7 +5385,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case SR_DRAGONCOMBO:
-	case SR_FLASHCOMBO_ATK_STEP1:
 		skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
 
@@ -5409,34 +5436,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		}
 		break;
 
-	case SR_TIGERCANNON:
-	case SR_FLASHCOMBO_ATK_STEP3:
-		if (flag&1) {
-			if (skill_area_temp[3] == skill_id && skill_area_temp_i64[0]) { // Safe check
-				if (skill_area_temp[1] != bl->id) {
-					int64 dmg = skill_area_temp_i64[0];
-					bool infdef = is_infinite_defense(bl, skill_get_type(skill_id));
-					if (infdef)
-						dmg = 1;
-					status_damage(src, bl, dmg, 0, 0, 0);
-					status_zap(bl, 0, status_get_max_sp(bl) * 10 / 100);
-					clif_skill_damage(src, bl, tick, status_get_amotion(bl), 0, dmg, 1, skill_id, skill_lv, 6);
-				}
-			}
-			else { // Somehow, we failed
-				skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
-				status_zap(bl, 0, status_get_max_sp(bl) * 10 / 100);
-			}
-		}
-		else if (sd) {
-			skill_area_temp[1] = bl->id;
-			skill_area_temp[3] = skill_id;
-			skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag|8); // Only do attack calculation once
-			status_zap(bl, 0, status_get_max_sp(bl) * 10 / 100);
-			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
-		}
-		break;
-
 	case SO_POISON_BUSTER: {
 			struct status_change *tsc2 = status_get_sc(bl);
 			if( tsc2 && tsc2->data[SC_POISON] ) {
@@ -6703,8 +6702,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case RK_STORMBLAST:
 	case NC_AXETORNADO:
 	case GC_COUNTERSLASH:
-	case SR_SKYNETBLOW:
-	case SR_FLASHCOMBO_ATK_STEP4:
 	case SR_RAMPAGEBLASTER:
 	case SR_HOWLINGOFLION:
 	case KO_HAPPOKUNAI:
@@ -6718,7 +6715,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 		else
 			i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src),
 				src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
-		if( !i && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) )
+		if( !i && ( skill_id == NC_AXETORNADO || skill_id == KO_HAPPOKUNAI ) )
 			clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
 		break;
 
@@ -9608,6 +9605,37 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			clif_skill_nodamage(bl,src,skill_id,skill_lv,
 				sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)));
 		break;
+
+	case SR_SKYNETBLOW: {
+			struct status_change *sc = status_get_sc(src);
+
+			clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SKILL);
+			skill_area_temp[1] = 0;
+			if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO)
+				map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1|4, skill_castend_damage_id);
+			else
+				map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+		}
+		break;
+
+	case SR_TIGERCANNON:
+		clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SKILL);
+		skill_area_temp[1] = bl->id;
+		if (flag&2) { // For SR_FLASHCOMBO
+			skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
+			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+		} else {
+			struct status_change *sc = status_get_sc(src);
+
+			if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) {
+				skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag|4);
+				map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1|4, skill_castend_damage_id);
+			} else {
+				skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
+				map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+			}
+		}
+		break;
 	case SR_CURSEDCIRCLE:
 		if( flag&1 ) {
 			if( is_boss(bl) ) break;
@@ -9702,15 +9730,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
 		break;
 	case SR_FLASHCOMBO: {
-		const int combo[] = { SR_FLASHCOMBO_ATK_STEP1, SR_FLASHCOMBO_ATK_STEP2, SR_FLASHCOMBO_ATK_STEP3, SR_FLASHCOMBO_ATK_STEP4 };
+		const int combo[] = { SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW };
 		const int delay[] = { 0, 250, 500, 2000 };
 
 		if (sd)
 			sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick;
-		clif_skill_nodamage(src,bl,skill_id,skill_lv,
-			sc_start2(src,bl,type,100,skill_lv,bl->id,skill_get_time(skill_id,skill_lv)));
-		for (i = 0; i < ARRAYLENGTH(combo); i++)
-			skill_addtimerskill(src,tick + delay[i],bl->id,0,0,combo[i],skill_lv,BF_WEAPON,flag|SD_LEVEL);
+		clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)));
+		for (i = 0; i < ARRAYLENGTH(combo); i++) {
+			if (combo[i] == SR_TIGERCANNON)
+				flag |= 2;
+			skill_addtimerskill(src, tick + delay[i], bl->id, 0, 0, combo[i], skill_lv, BF_WEAPON, flag);
+		}
 	}
 	break;
 
@@ -15388,7 +15418,10 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id,
 	require = skill_get_requirement(sd,skill_id,skill_lv);
 
 	if( require.hp > 0 && status->hp <= (unsigned int)require.hp) {
-		clif_skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0);
+		if (skill_id == SR_TIGERCANNON)
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
+		else
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_HP_INSUFFICIENT, 0);
 		return false;
 	}
 
@@ -16133,8 +16166,6 @@ int skill_delayfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv)
 		case CH_CHAINCRUSH:
 		case SR_DRAGONCOMBO:
 		case SR_FALLENEMPIRE:
-		case SR_FLASHCOMBO_ATK_STEP1:
-		case SR_FLASHCOMBO_ATK_STEP2:
 			//If delay not specified, it will be 1000 - 4*agi - 2*dex
 			if (time == 0)
 				time = 1000;

+ 0 - 4
src/map/skill.h

@@ -1725,10 +1725,6 @@ enum e_skill {
 	WL_TELEKINESIS_INTENSE,
 	LG_KINGS_GRACE,
 	ALL_FULL_THROTTLE,
-	SR_FLASHCOMBO_ATK_STEP1, // SR_DRAGONCOMBO
-	SR_FLASHCOMBO_ATK_STEP2, // SR_FALLENEMPIRE
-	SR_FLASHCOMBO_ATK_STEP3, // SR_TIGERCANNON
-	SR_FLASHCOMBO_ATK_STEP4, // SR_SKYNETBLOW
 
 	HLIF_HEAL = 8001,
 	HLIF_AVOID,

+ 0 - 1
src/map/status.c

@@ -717,7 +717,6 @@ void initChangeTables(void)
 	set_sc( SR_GENTLETOUCH_CHANGE		, SC_GT_CHANGE		, SI_GENTLETOUCH_CHANGE		, SCB_WATK|SCB_MDEF|SCB_ASPD );
 	set_sc( SR_GENTLETOUCH_REVITALIZE	, SC_GT_REVITALIZE	, SI_GENTLETOUCH_REVITALIZE	, SCB_MAXHP|SCB_REGEN );
 	set_sc( SR_FLASHCOMBO			, SC_FLASHCOMBO		, SI_FLASHCOMBO			, SCB_NONE );
-	add_sc( SR_FLASHCOMBO_ATK_STEP1	, SC_STUN		);
 
 	/* Wanderer / Minstrel */
 	set_sc( WA_SWING_DANCE			, SC_SWINGDANCE			, SI_SWINGDANCE			, SCB_SPEED|SCB_ASPD );