Przeglądaj źródła

Initial implementation of Sky Emperor (#8934)

Taken from #7024

Co-authored-by: munkrej <schmunk@posteo.de>
Co-authored-by: Atemo <Atemo@users.noreply.github.com>
Lemongrass3110 3 miesięcy temu
rodzic
commit
f5d02e34c5

+ 407 - 0
db/re/skill_db.yml

@@ -43948,6 +43948,413 @@ Body:
       SpCost: 150
       ApCost: 150
     Status: Rulebreak
+  - Id: 5463
+    Name: SKE_SKY_MASTERY
+    Description: Sky Mastery
+    MaxLevel: 10
+  - Id: 5464
+    Name: SKE_WAR_BOOK_MASTERY
+    Description: War Book Mastery
+    MaxLevel: 10
+  - Id: 5465
+    Name: SKE_RISING_SUN
+    Description: Rising Sun
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Attack
+    Range: 2
+    Hit: Multi_Hit
+    HitCount: -2
+    Element: Weapon
+    AfterCastActDelay: 500
+    Cooldown: 500
+    Duration1: 
+     - Level: 1
+       Time: 30000
+     - Level: 2
+       Time: 60000
+     - Level: 3
+       Time: 90000
+     - Level: 4
+       Time: 120000
+     - Level: 5
+       Time: 150000
+    Duration2: 1000
+    Requires:
+      SpCost: 60
+  - Id: 5466
+    Name: SKE_NOON_BLAST
+    Description: Noon Blast
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Attack
+    DamageFlags:
+      Splash: true
+      Critical: true
+    Range: 2
+    Hit: Multi_Hit
+    HitCount: -2
+    GiveAp: 3
+    Element: Weapon
+    SplashArea:
+      - Level: 1
+        Area: 1
+      - Level: 2
+        Area: 1
+      - Level: 3
+        Area: 2
+      - Level: 4
+        Area: 2
+      - Level: 5
+        Area: 3
+    AfterCastActDelay: 500
+    Cooldown: 700
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 49
+        - Level: 2
+          Amount: 53
+        - Level: 3
+          Amount: 57
+        - Level: 4
+          Amount: 61
+        - Level: 5
+          Amount: 65
+  - Id: 5467
+    Name: SKE_SUNSET_BLAST
+    Description: Sunset Blast
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Attack
+    DamageFlags:
+      Splash: true
+      Critical: true
+    Range: 2
+    Hit: Multi_Hit
+    HitCount: -2
+    GiveAp: 3
+    Element: Weapon
+    SplashArea:
+      - Level: 1
+        Area: 1
+      - Level: 2
+        Area: 1
+      - Level: 3
+        Area: 2
+      - Level: 4
+        Area: 2
+      - Level: 5
+        Area: 3
+    AfterCastActDelay: 500
+    Cooldown: 300
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 46
+        - Level: 2
+          Amount: 50
+        - Level: 3
+          Amount: 54
+        - Level: 4
+          Amount: 58
+        - Level: 5
+          Amount: 62
+  - Id: 5468
+    Name: SKE_RISING_MOON
+    Description: Rising Moon
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Self
+    DamageFlags:
+      Splash: true
+    Range: 2
+    Hit: Multi_Hit
+    HitCount: -2
+    Element: Weapon
+    SplashArea:
+      - Level: 1
+        Area: 2
+      - Level: 2
+        Area: 2
+      - Level: 3
+        Area: 3
+      - Level: 4
+        Area: 3
+      - Level: 5
+        Area: 4
+    AfterCastActDelay: 500
+    Cooldown: 500
+    Duration1: 
+     - Level: 1
+       Time: 30000
+     - Level: 2
+       Time: 60000
+     - Level: 3
+       Time: 90000
+     - Level: 4
+       Time: 120000
+     - Level: 5
+       Time: 150000
+    Duration2: 1000
+    Requires:
+      SpCost: 64
+  - Id: 5469
+    Name: SKE_MIDNIGHT_KICK
+    Description: Midnight Kick
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Self
+    DamageFlags:
+      Splash: true
+    Range: 1
+    Hit: Multi_Hit
+    HitCount: -2
+    GiveAp: 3
+    Element: Weapon
+    SplashArea:
+      - Level: 1
+        Area: 2
+      - Level: 2
+        Area: 2
+      - Level: 3
+        Area: 3
+      - Level: 4
+        Area: 3
+      - Level: 5
+        Area: 4
+    CastCancel: true
+    CastTime: 1000
+    Cooldown: 700
+    FixedCastTime: 500
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 60
+        - Level: 2
+          Amount: 62
+        - Level: 3
+          Amount: 64
+        - Level: 4
+          Amount: 66
+        - Level: 5
+          Amount: 68
+  - Id: 5470
+    Name: SKE_DAWN_BREAK
+    Description: Dawn Break
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Self
+    DamageFlags:
+      Splash: true
+    Range: 1
+    Hit: Multi_Hit
+    HitCount: -2
+    GiveAp: 3
+    Element: Weapon
+    SplashArea:
+      - Level: 1
+        Area: 2
+      - Level: 2
+        Area: 2
+      - Level: 3
+        Area: 3
+      - Level: 4
+        Area: 3
+      - Level: 5
+        Area: 4
+    CastCancel: true
+    CastTime: 1000
+    Cooldown: 300
+    FixedCastTime: 500
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 56
+        - Level: 2
+          Amount: 58
+        - Level: 3
+          Amount: 60
+        - Level: 4
+          Amount: 62
+        - Level: 5
+          Amount: 64
+  - Id: 5471
+    Name: SKE_TWINKLING_GALAXY
+    Description: Twinkling Galaxy
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Self
+    DamageFlags:
+      Splash: true
+    Range: 1
+    Hit: Multi_Hit
+    HitCount: -3
+    Element: Weapon
+    SplashArea: 2
+    CastCancel: true
+    CastTime: 1000
+    Cooldown: 5000
+    FixedCastTime: 500
+    Duration1: 4500
+    Requires:
+      SpCost: 84
+    Unit:
+      Id: TWINKLING_GALAXY
+      Range:
+        - Level: 1
+          Size: 6
+        - Level: 2
+          Size: 6
+        - Level: 3
+          Size: 5
+        - Level: 4
+          Size: 5
+        - Level: 5
+          Size: 4
+      Interval: 300
+      Target: Enemy
+      Flag:
+        PathCheck: true
+  - Id: 5472
+    Name: SKE_STAR_BURST
+    Description: Star Burst
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Attack
+    Range: 2
+    Hit: Multi_hit
+    HitCount: -2
+    GiveAp: 3
+    Element: Weapon
+    AfterCastActDelay: 500
+    Cooldown: 1000
+    CastCancel: true
+    FixedCastTime: 500
+    Duration1: 100
+    Duration2: 4500
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 54
+        - Level: 2
+          Amount: 56
+        - Level: 3
+          Amount: 58
+        - Level: 4
+          Amount: 60
+        - Level: 5
+          Amount: 62
+    Unit:
+      Id: STAR_BURST
+      Range: 2
+      Interval: 300
+      Target: Enemy
+      Flag:
+        PathCheck: true
+    Status: Star_Burst
+  - Id: 5473
+    Name: SKE_STAR_CANNON
+    Description: Star Cannon
+    MaxLevel: 5
+    Type: Weapon
+    TargetType: Self
+    DamageFlags:
+      Splash: true
+    Range: 1
+    Hit: Multi_Hit
+    HitCount: -3
+    GiveAp: 3
+    Element: Weapon
+    SplashArea: 3
+    Cooldown: 5000
+    CastCancel: true
+    FixedCastTime: 500
+    Duration1: 4500
+    Requires:
+      SpCost:
+        - Level: 1
+          Amount: 51
+        - Level: 2
+          Amount: 54
+        - Level: 3
+          Amount: 57
+        - Level: 4
+          Amount: 60
+        - Level: 5
+          Amount: 63
+    Unit:
+      Id: STAR_CANNON
+      Range:
+        - Level: 1
+          Size: 6
+        - Level: 2
+          Size: 6
+        - Level: 3
+          Size: 5
+        - Level: 4
+          Size: 5
+        - Level: 5
+          Size: 4
+      Interval: 300
+      Target: Enemy
+      Flag:
+        PathCheck: true
+  - Id: 5474
+    Name: SKE_ALL_IN_THE_SKY
+    Description: All in the Sky
+    MaxLevel: 10
+    Type: Weapon
+    TargetType: Attack
+    DamageFlags:
+      Critical: true
+    Range: -9
+    Hit: Multi_Hit
+    HitCount: 1
+    Element: Weapon
+    CastCancel: true
+    FixedCastTime: 1000
+    Cooldown: 2000
+    Requires:
+      ApCost: 35
+      SpCost: 85
+  - Id: 5475
+    Name: SKE_ENCHANTING_SKY
+    Description: Enchanting Sky
+    MaxLevel: 10
+    Type: Magic
+    TargetType: Self
+    DamageFlag:
+       NoDamage: true
+    CastCancel: true
+    CastTime: 300
+    FixedCastTime: 1000
+    Cooldown: 60000
+    Duration1: 
+     - Level: 1
+       Time: 90000
+     - Level: 2
+       Time: 180000
+     - Level: 3
+       Time: 270000
+     - Level: 4
+       Time: 360000
+     - Level: 5
+       Time: 450000
+     - Level: 6
+       Time: 540000
+     - Level: 7
+       Time: 630000
+     - Level: 8
+       Time: 720000
+     - Level: 9
+       Time: 810000
+     - Level: 10
+       Time: 900000
+    Requires:
+      ApCost: 150
+      SpCost: 100
+    Status: Sky_Enchant
   - Id: 5496
     Name: NW_THE_VIGILANTE_AT_NIGHT_GUN_GATLING
     Description: The Vigilante At Night Gun Gatling

+ 89 - 0
db/re/skill_tree.yml

@@ -8298,3 +8298,92 @@ Body:
             Level: 1
           - Name: SH_MYSTICAL_CREATURE_MASTERY
             Level: 10
+  - Job: Sky_Emperor
+    Inherit:
+      Novice: true
+      Taekwon: true
+      Star_Gladiator: true
+      Star_Emperor: true
+    Tree:
+      - Name: SKE_WAR_BOOK_MASTERY
+        MaxLevel: 10
+      - Name: SKE_SKY_MASTERY
+        MaxLevel: 10
+      - Name: SKE_RISING_SUN
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 1
+      - Name: SKE_RISING_MOON
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 1
+      - Name: SKE_TWINKLING_GALAXY
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 1
+      - Name: SKE_NOON_BLAST
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 3
+          - Name: SKE_RISING_SUN
+            Level: 1
+      - Name: SKE_MIDNIGHT_KICK
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 3
+          - Name: SKE_RISING_MOON
+            Level: 1
+      - Name: SKE_STAR_BURST
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 3
+          - Name: SKE_TWINKLING_GALAXY
+            Level: 1
+      - Name: SKE_SUNSET_BLAST
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 5
+          - Name: SKE_NOON_BLAST
+            Level: 1
+      - Name: SKE_DAWN_BREAK
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 5
+          - Name: SKE_MIDNIGHT_KICK
+            Level: 1
+      - Name: SKE_STAR_CANNON
+        MaxLevel: 5
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 5
+          - Name: SKE_STAR_BURST
+            Level: 1
+      - Name: SKE_ALL_IN_THE_SKY
+        MaxLevel: 10
+        Requires:
+          - Name: SKE_WAR_BOOK_MASTERY
+            Level: 5
+          - Name: SKE_RISING_SUN
+            Level: 1
+          - Name: SKE_RISING_MOON
+            Level: 1
+      - Name: SKE_ENCHANTING_SKY
+        MaxLevel: 10
+        Requires:
+          - Name: SKE_SKY_MASTERY
+            Level: 5
+  - Job: Sky_Emperor2
+    Inherit:
+      Novice: true
+      Taekwon: true
+      Star_Gladiator: true
+      Star_Emperor: true
+      Sky_Emperor: true

+ 57 - 0
db/re/status.yml

@@ -9689,3 +9689,60 @@ Body:
       NoDispell: true
       # NoBanishingBuster: true  # !TODO
       # NoClearance: true  # !TODO
+  - Status: Rising_Sun
+    Icon: EFST_RISING_SUN
+    DurationLookup: SKE_RISING_SUN
+    Fail:
+      Rising_Moon: true
+      Midnight_Moon: true
+      Sky_Enchant: true
+    EndOnStart:
+      Dawn_Moon: true
+  - Status: Noon_Sun
+    Icon: EFST_NOON_SUN
+    DurationLookup: SKE_RISING_SUN
+    EndOnStart:
+      Rising_Sun: true
+  - Status: Sunset_Sun
+    Icon: EFST_SUNSET_SUN
+    DurationLookup: SKE_RISING_SUN
+    EndOnStart:
+      Noon_Sun: true
+    Fail:
+      Sunset_Sun: true
+  - Status: Rising_Moon
+    Icon: EFST_RISING_MOON
+    DurationLookup: SKE_RISING_MOON
+    Fail:
+      Rising_Sun: true
+      Noon_Sun: true
+      Sky_Enchant: true
+    EndOnStart:
+      Sunset_Sun: true
+  - Status: Midnight_Moon
+    Icon: EFST_MIDNIGHT_MOON
+    DurationLookup: SKE_RISING_MOON
+    EndOnStart:
+      Rising_Moon: true
+  - Status: Dawn_Moon
+    Icon: EFST_DAWN_MOON
+    DurationLookup: SKE_RISING_MOON
+    EndOnStart:
+      Midnight_Moon: true
+    Fail:
+      Dawn_Moon: true
+  - Status: Star_Burst
+    Icon: EFST_STAR_BURST
+    DurationLookup: SKE_STAR_BURST
+    Flags:
+      BlEffect: true
+  - Status: Sky_Enchant
+    Icon: EFST_SKY_ENCHANT
+    DurationLookup: SKE_ENCHANTING_SKY
+    EndOnStart:
+      Rising_Sun: true
+      Noon_Sun: true
+      Sunset_Sun: true
+      Rising_Moon: true
+      Midnight_Moon: true
+      Dawn_Moon: true

+ 101 - 0
src/map/battle.cpp

@@ -3022,6 +3022,28 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct
 				}
 
 				return false;
+
+			case SKE_NOON_BLAST:
+				if( sc == nullptr ){
+					return false;
+				}
+
+				if( sc->getSCE( SC_NOON_SUN ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ){
+					return false;
+				}
+
+				break;
+
+			case SKE_SUNSET_BLAST:
+				if( sc == nullptr ){
+					return false;
+				}
+
+				if( sc->getSCE( SC_SUNSET_SUN ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ){
+					return false;
+				}
+
+				break;
 		}
 		if(tsd && tsd->bonus.critical_def)
 			cri = cri * ( 100 - tsd->bonus.critical_def ) / 100;
@@ -6370,6 +6392,85 @@ static int32 battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list
 			}
 			RE_LVL_DMOD(100);
 			break;
+		case SKE_MIDNIGHT_KICK:
+			skillratio += -100 + 600 + 1200  * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+
+			if( sc != nullptr && ( sc->getSCE( SC_MIDNIGHT_MOON ) != nullptr || sc->getSCE( SC_SKY_ENCHANT ) != nullptr ) ){
+				skillratio += 950 + 250 * skill_lv;
+			}
+
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_ALL_IN_THE_SKY:
+			skillratio += -100 + 3000 + 2000 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			if (status_get_race(target) == RC_DEMIHUMAN || status_get_race(target) == RC_DEMON)
+				wd->div_ = 3;
+			break;
+
+		case SKE_TWINKLING_GALAXY:
+			skillratio += -100 + 200 + 400 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 3 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_STAR_CANNON:
+			skillratio += -100 + 200 + 500 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_STAR_BURST:
+			skillratio += -100 + 500 + 400 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 3 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_DAWN_BREAK:
+			skillratio += -100 + 400 + 400 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+
+			if( sc != nullptr && ( sc->getSCE( SC_DAWN_MOON ) != nullptr || sc->getSCE( SC_SKY_ENCHANT ) != nullptr ) ){
+				skillratio += 200 * skill_lv;
+			}
+
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_SUNSET_BLAST:
+			skillratio += -100 + 950 + 400 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_RISING_MOON:
+			skillratio += -100 + 700 + 450 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_NOON_BLAST:
+			skillratio += -100 + 1500 + 1250 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
+
+		case SKE_RISING_SUN:
+			skillratio += -100 + 500 + 600 * skill_lv;
+			skillratio += pc_checkskill( sd, SKE_SKY_MASTERY ) * 5 * skill_lv;
+			skillratio += 5 * sstatus->pow;
+			RE_LVL_DMOD(100);
+			break;
 	}
 	return skillratio;
 }

+ 9 - 0
src/map/script_constants.hpp

@@ -1954,6 +1954,14 @@
 	export_constant(SC_TEMPORARY_COMMUNION);
 	export_constant(SC_BLESSING_OF_M_CREATURES);
 	export_constant(SC_BLESSING_OF_M_C_DEBUFF);
+	export_constant(SC_RISING_SUN);
+	export_constant(SC_NOON_SUN);
+	export_constant(SC_SUNSET_SUN);
+	export_constant(SC_RISING_MOON);
+	export_constant(SC_MIDNIGHT_MOON);
+	export_constant(SC_DAWN_MOON);
+	export_constant(SC_STAR_BURST);
+	export_constant(SC_SKY_ENCHANT);
 
 /// Do not modify code below this, until the end of the API hook, since it will be automatically generated again
 /// @APIHOOK_START(EFST_CONST)
@@ -10278,6 +10286,7 @@
 	export_constant(UNT_JACK_FROST_NOVA);
 	export_constant(UNT_GROUND_GRAVITATION);
 	export_constant(UNT_KUNAIWAIKYOKU);
+	export_constant(UNT_STAR_BURST);
 	export_constant(UNT_GD_LEADERSHIP);
 	export_constant(UNT_GD_GLORYWOUNDS);
 	export_constant(UNT_GD_SOULCOLD);

+ 232 - 0
src/map/skill.cpp

@@ -4826,6 +4826,27 @@ static TIMER_FUNC(skill_timerskill){
 							src, skl->skill_id, skl->skill_lv, tick, skl->flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
 					}
 					break;
+
+				case SKE_TWINKLING_GALAXY:{
+						int32 area = skill_get_unit_range( skl->skill_id, skl->skill_lv );
+						int32 splash = skill_get_splash( skl->skill_id, skl->skill_lv );
+						int16 tmpx = skl->x - area + rnd() % ( area * 2 + 1 );
+						int16 tmpy = skl->y - area + rnd() % ( area * 2 + 1 );
+
+						map_foreachinarea( skill_area_sub, src->m, tmpx - splash, tmpy - splash, tmpx + splash, tmpy + splash, BL_CHAR, src, skl->skill_id, skl->skill_lv, tick, skl->flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id );
+					} break;
+
+				case SKE_STAR_CANNON: {
+						int32 area = skill_get_unit_range( skl->skill_id, skl->skill_lv );
+						int32 splash = skill_get_splash( skl->skill_id, skl->skill_lv );
+
+						for( int32 i = 0, stars = 1 + ( skl->skill_lv + 1 ) / 2; i < stars; i++) {
+							int16 tmpx = skl->x - area + rnd() % ( area * 2 + 1 );
+							int16 tmpy = skl->y - area + rnd() % ( area * 2 + 1 );
+
+							map_foreachinarea( skill_area_sub, src->m, tmpx - splash, tmpy - splash, tmpx + splash, tmpy + splash, BL_CHAR, src, skl->skill_id, skl->skill_lv, tick, skl->flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id );
+						}
+					} break;
 			}
 		}
 	} while (0);
@@ -5270,6 +5291,9 @@ int32 skill_castend_damage_id (struct block_list* src, struct block_list *bl, ui
 	case NW_HASTY_FIRE_IN_THE_HOLE:
 	case NW_BASIC_GRENADE:
 	case NW_WILD_FIRE:
+	case SKE_MIDNIGHT_KICK:
+	case SKE_DAWN_BREAK:
+	case SKE_RISING_MOON:
 		skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
 		break;
 	case DK_DRAGONIC_AURA:
@@ -5746,6 +5770,8 @@ int32 skill_castend_damage_id (struct block_list* src, struct block_list *bl, ui
 	case SOA_TALISMAN_OF_RED_PHOENIX:
 	case SOA_TALISMAN_OF_FOUR_BEARING_GOD:
 	case SOA_CIRCLE_OF_DIRECTIONS_AND_ELEMENTALS:
+	case SKE_SUNSET_BLAST:
+	case SKE_NOON_BLAST:
 		if( flag&1 ) {//Recursive invocation
 			int32 sflag = skill_area_temp[0] & 0xFFF;
 			int32 heal = 0;
@@ -5818,6 +5844,8 @@ int32 skill_castend_damage_id (struct block_list* src, struct block_list *bl, ui
 				case MT_SPARK_BLASTER:
 				case HN_JUPITEL_THUNDER_STORM:
 				case SOA_TALISMAN_OF_FOUR_BEARING_GOD:
+				case SKE_SUNSET_BLAST:
+				case SKE_NOON_BLAST:
 					clif_skill_nodamage(src,*bl,skill_id,skill_lv);
 					break;
 #ifdef RENEWAL
@@ -6019,6 +6047,85 @@ int32 skill_castend_damage_id (struct block_list* src, struct block_list *bl, ui
 		}
 		break;
 
+	case SKE_RISING_SUN:
+		clif_skill_nodamage(src, *bl, skill_id, skill_lv);
+		skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+
+		if ( sc == nullptr || ( sc->getSCE( SC_RISING_SUN ) == nullptr && sc->getSCE( SC_NOON_SUN ) == nullptr && sc->getSCE( SC_SUNSET_SUN ) == nullptr ) ){
+			sc_start(src, src, SC_RISING_SUN, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+		}else if( sc->getSCE( SC_NOON_SUN ) == nullptr && sc->getSCE( SC_SUNSET_SUN ) == nullptr ){
+			sc_start(src, src, SC_NOON_SUN, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+		}else if( sc->getSCE( SC_SUNSET_SUN ) == nullptr ){
+			sc_start(src, src, SC_SUNSET_SUN, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+		}
+
+		break;
+
+	case SKE_TWINKLING_GALAXY:
+	case SKE_STAR_CANNON:
+		if (flag & 1)
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		break;
+
+	case SKE_STAR_BURST:
+		if (flag & 1) {
+			skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		} else {
+			unit_data* ud = unit_bl2ud( src );
+
+			if( ud != nullptr ){
+				for( const std::shared_ptr<s_skill_unit_group>& sug : ud->skillunits ){
+					if( sug->skill_id != SKE_TWINKLING_GALAXY ){
+						continue;
+					}
+
+					skill_unit* su = sug->unit;
+
+					// Check if it is too far away
+					if( distance_xy( bl->x, bl->y, su->bl.x, su->bl.y ) > skill_get_unit_range( sug->skill_id, sug->skill_lv ) ){
+						continue;
+					}
+
+					std::shared_ptr<s_skill_unit_group> sg = su->group;
+
+					for( int32 i = 0; i < MAX_SKILLTIMERSKILL; i++ ){
+						if( ud->skilltimerskill[i] == nullptr ){
+							continue;
+						}
+
+						if( ud->skilltimerskill[i]->skill_id != sug->skill_id ){
+							continue;
+						}
+
+						delete_timer(ud->skilltimerskill[i]->timer, skill_timerskill);
+						ers_free(skill_timer_ers, ud->skilltimerskill[i]);
+						ud->skilltimerskill[i] = nullptr;
+					}
+
+					skill_delunitgroup(sg);
+					sc_start2(src, bl, skill_get_sc(skill_id), 100, skill_lv, src->id, skill_get_time2(skill_id, skill_lv));
+
+					return skill_castend_pos2(src, bl->x, bl->y, skill_id, skill_lv, tick, 0);
+				}
+			}
+
+			if( sd != nullptr ){
+				clif_skill_fail(*sd, skill_id, USESKILL_FAIL_LEVEL);
+			}
+
+			return 1;
+		}
+		break;
+
+	case SKE_ALL_IN_THE_SKY:
+		if (bl->type == BL_PC)
+			status_zap(bl, 0, 0, status_get_ap(bl));
+		if( unit_movepos( src, bl->x, bl->y, 2, true ) ){
+			clif_snap(src, src->x, src->y);
+		}
+		skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
+		break;
+
 	//Place units around target
 	case NJ_BAKUENRYU:
 		clif_skill_nodamage(src, *bl, skill_id, skill_lv);
@@ -8076,6 +8183,7 @@ int32 skill_castend_nodamage_id (struct block_list *src, struct block_list *bl,
 	case HN_BREAKINGLIMIT:
 	case HN_RULEBREAK:
 	case SH_TEMPORARY_COMMUNION:
+	case SKE_ENCHANTING_SKY:
 		clif_skill_nodamage(src,*bl,skill_id,skill_lv,
 			sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv)));
 		break;
@@ -8683,6 +8791,9 @@ int32 skill_castend_nodamage_id (struct block_list *src, struct block_list *bl,
 	case BO_EXPLOSIVE_POWDER:
 	case SOA_EXORCISM_OF_MALICIOUS_SOUL:
 	case SOA_TALISMAN_OF_WHITE_TIGER:
+	case SKE_DAWN_BREAK:
+	case SKE_RISING_MOON:
+	case SKE_MIDNIGHT_KICK:
 	{
 		int32 starget = BL_CHAR|BL_SKILL;
 
@@ -8727,6 +8838,18 @@ int32 skill_castend_nodamage_id (struct block_list *src, struct block_list *bl,
 					sc_start(src, src, skill_get_sc(skill_id), 100, skill_lv, skill_get_time(skill_id, skill_lv));
 				}
 				break;
+
+			case SKE_RISING_MOON:
+				if( sc == nullptr || ( sc->getSCE( SC_RISING_MOON ) == nullptr && sc->getSCE( SC_MIDNIGHT_MOON ) == nullptr && sc->getSCE( SC_DAWN_MOON ) == nullptr ) ){
+					sc_start(src, src, SC_RISING_MOON, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+				}else if( sc->getSCE( SC_MIDNIGHT_MOON ) == nullptr && sc->getSCE( SC_DAWN_MOON ) == nullptr ){
+					sc_start(src, src, SC_MIDNIGHT_MOON, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+				}else if( sc->getSCE( SC_DAWN_MOON ) == nullptr ){
+					sc_start(src, src, SC_DAWN_MOON, 100, skill_lv, skill_get_time(skill_id, skill_lv));
+				}else if( sc->getSCE( SC_RISING_SUN ) != nullptr ){
+					status_change_end(bl, SC_DAWN_MOON);
+				}
+				break;
 		}
 
 		skill_area_temp[1] = 0;
@@ -13423,6 +13546,37 @@ static int8 skill_castend_id_check(struct block_list *src, struct block_list *ta
 				return USESKILL_FAIL_TOTARGET;
 			}
 			break;
+
+		case SKE_STAR_BURST:
+		case SKE_STAR_CANNON: {
+				unit_data* ud = unit_bl2ud( src );
+
+				if( ud == nullptr ){
+					return USESKILL_FAIL_NEED_TWINKLING_GALAXY;
+				}
+
+				bool ok = false;
+
+				for( const std::shared_ptr<s_skill_unit_group>& sug : ud->skillunits ){
+					if( sug->skill_id != SKE_TWINKLING_GALAXY ){
+						continue;
+					}
+
+					skill_unit* su = sug->unit;
+					std::shared_ptr<s_skill_unit_group> sg = su->group;
+
+					if( distance_xy( src->x, src->y, su->bl.x, su->bl.y ) > skill_get_unit_range( sug->skill_id, sug->skill_lv ) ){
+						continue;
+					}
+
+					ok = true;
+					break;
+				}
+
+				if( !ok ){
+					return USESKILL_FAIL_NEED_TWINKLING_GALAXY;
+				}
+			} break;
 	}
 
 	if (inf&INF_ATTACK_SKILL ||
@@ -15091,6 +15245,59 @@ int32 skill_castend_pos2(struct block_list* src, int32 x, int32 y, uint16 skill_
 		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
 		break;
 
+	case SKE_TWINKLING_GALAXY:
+		for (i = 0; i < skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id); i++)
+			skill_addtimerskill(src, tick + (t_tick)i*skill_get_unit_interval(skill_id), 0, x, y, skill_id, skill_lv, 0, flag);
+		flag |= 1;
+		skill_unitsetting(src, skill_id, skill_lv, x, y, 0);
+		break;
+	case SKE_STAR_BURST:
+		flag |= 1;
+		skill_unitsetting(src, skill_id, skill_lv, x, y, 0);
+		break;
+	case SKE_STAR_CANNON: {
+			unit_data* ud = unit_bl2ud( src );
+
+			if( ud == nullptr ){
+				break;
+			}
+
+			for( const std::shared_ptr<s_skill_unit_group>& sug : ud->skillunits ){
+				if( sug->skill_id != SKE_TWINKLING_GALAXY ){
+					continue;
+				}
+
+				skill_unit* su = sug->unit;
+
+				if( distance_xy( x, y, su->bl.x, su->bl.y ) > skill_get_unit_range( sug->skill_id, sug->skill_lv ) ){
+					continue;
+				}
+
+				std::shared_ptr<s_skill_unit_group> sg = su->group;
+				
+				for( int32 i = 0; i< MAX_SKILLTIMERSKILL; i++ ){
+					if( ud->skilltimerskill[i] == nullptr ){
+						continue;
+					}
+
+					if( ud->skilltimerskill[i]->skill_id != SKE_TWINKLING_GALAXY ){
+						continue;
+					}
+						
+					delete_timer(ud->skilltimerskill[i]->timer, skill_timerskill);
+					ers_free(skill_timer_ers, ud->skilltimerskill[i]);
+					ud->skilltimerskill[i] = nullptr;
+				}
+
+				skill_delunitgroup(sg);
+
+				for (i = 0; i < skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id); i++)
+					skill_addtimerskill(src, tick + (t_tick)i*skill_get_unit_interval(skill_id), 0, x, y, skill_id, skill_lv, 0, flag);
+				flag |= 1;
+				skill_unitsetting(src, skill_id, skill_lv, x, y, 0);
+			}
+		} break;
+
 	default:
 		ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id);
 		return 1;
@@ -16403,6 +16610,7 @@ int32 skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t
 		case UNT_SOLIDTRAP:
 		case UNT_SWIFTTRAP:
 		case UNT_FLAMETRAP:
+		case UNT_STAR_BURST:
 			skill_attack(skill_get_type(sg->skill_id),ss,&unit->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
 			break;
 #ifdef RENEWAL
@@ -18541,6 +18749,30 @@ bool skill_check_condition_castbegin( map_session_data& sd, uint16 skill_id, uin
 				return false;
 			}
 			break;
+		case SKE_NOON_BLAST:
+			if( sc == nullptr || ( sc->getSCE( SC_RISING_SUN ) == nullptr && sc->getSCE( SC_NOON_SUN ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ) ){
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION);
+				return false;
+			}
+			break;
+		case SKE_SUNSET_BLAST:
+			if( sc == nullptr || ( sc->getSCE( SC_SUNSET_SUN ) == nullptr && sc->getSCE( SC_NOON_SUN ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ) ){
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION);
+				return false;
+			}
+			break;
+		case SKE_MIDNIGHT_KICK:
+			if( sc == nullptr || ( sc->getSCE( SC_RISING_MOON ) == nullptr && sc->getSCE( SC_MIDNIGHT_MOON ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ) ){
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION);
+				return false;
+			}
+			break;
+		case SKE_DAWN_BREAK:
+			if( sc == nullptr || ( sc->getSCE( SC_DAWN_MOON ) == nullptr && sc->getSCE( SC_MIDNIGHT_MOON ) == nullptr && sc->getSCE( SC_SKY_ENCHANT ) == nullptr ) ){
+				clif_skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION);
+				return false;
+			}
+			break;
 	}
 
 	/* check state required */

+ 2 - 0
src/map/skill.hpp

@@ -2735,6 +2735,8 @@ enum e_skill_unit_id : uint16 {
 
 	UNT_KUNAIWAIKYOKU = 298, // Kunai - Distortion
 
+	UNT_STAR_BURST = 2409,
+
 	// Skill units outside the normal unit range.
 	UNT_DEEPBLINDTRAP = 20852,
 	UNT_SOLIDTRAP,

+ 20 - 0
src/map/status.cpp

@@ -4383,6 +4383,8 @@ int32 status_calc_pc_sub(map_session_data* sd, uint8 opt)
 		base_status->hit += 20;
 	if ((skill = pc_checkskill_imperial_guard(sd, 2)) > 0)// IG_SPEAR_SWORD_M
 		base_status->hit += skill * 3;
+	if (sd->status.weapon == W_BOOK && (skill = pc_checkskill(sd, SKE_WAR_BOOK_MASTERY)) > 0)
+		base_status->hit += skill * 3;
 
 	if ((skill = pc_checkskill(sd, SU_SOULATTACK)) > 0)
 		base_status->rhw.range += skill_get_range2(&sd->bl, SU_SOULATTACK, skill, true);
@@ -4429,6 +4431,8 @@ int32 status_calc_pc_sub(map_session_data* sd, uint8 opt)
 		base_status->patk += skill + 2;
 	if ((skill = pc_checkskill(sd, SOA_TALISMAN_MASTERY)) > 0)
 		base_status->smatk += skill;
+	if (sd->status.weapon == W_BOOK && (skill = pc_checkskill(sd, SKE_WAR_BOOK_MASTERY)) > 0)
+		base_status->patk += skill+2;
 
 	// 2-Handed Staff Mastery
 	if( sd->status.weapon == W_2HSTAFF && ( skill = pc_checkskill( sd, AG_TWOHANDSTAFF ) ) > 0 ){
@@ -9241,6 +9245,8 @@ static int32 status_get_sc_interval(enum sc_type type)
 			return 3000;
 		case SC_SHIELDSPELL_SP:
 			return 5000;
+		case SC_STAR_BURST:
+			return 300;
 		default:
 			break;
 	}
@@ -12544,6 +12550,10 @@ int32 status_change_start(struct block_list* src, struct block_list* bl,enum sc_
 		case SC_COLORS_OF_HYUN_ROK_BUFF:
 			val2 = 50;
 			break;
+		case SC_STAR_BURST:
+			tick_time = status_get_sc_interval(type);
+			val4 = tick - tick_time; // Remaining time
+			break;
 
 		default:
 			if (calc_flag.none() && scdb->skill_id == 0 && scdb->icon == EFST_BLANK && scdb->opt1 == OPT1_NONE && scdb->opt2 == OPT2_NONE && scdb->state.none() && scdb->flag.none() && scdb->endonstart.empty() && scdb->endreturn.empty() && scdb->fail.empty() && scdb->endonend.empty()) {
@@ -14689,6 +14699,16 @@ TIMER_FUNC(status_change_timer){
 			return 0;
 		}
 		break;
+
+	case SC_STAR_BURST:
+		if (sce->val4 >= 0) {
+			block_list* src = map_id2bl( sce->val2 );
+
+			if( src != nullptr && tid != INVALID_TIMER ){
+				skill_unitsetting(src, SKE_STAR_BURST, sce->val1, bl->x, bl->y, 0);
+			}
+		}
+		break;
 	}
 
 	// If status has an interval and there is at least 100ms remaining time, wait for next interval

+ 10 - 0
src/map/status.hpp

@@ -1375,6 +1375,16 @@ enum sc_type : int16 {
 	SC_BLESSING_OF_M_CREATURES,
 	SC_BLESSING_OF_M_C_DEBUFF,
 
+	// Sky Emperor
+	SC_RISING_SUN,
+	SC_NOON_SUN,
+	SC_SUNSET_SUN,
+	SC_RISING_MOON,
+	SC_MIDNIGHT_MOON,
+	SC_DAWN_MOON,
+	SC_STAR_BURST,
+	SC_SKY_ENCHANT,
+
 	SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
 };