Browse Source

Job Improvement Project - Warlock (#4897)

* Fixes #4706.
* kRO Changelog: http://ro.gnjoy.com/news/update/View.asp?seq=239&curpage=1
Thanks to @LordWhiplash,  @Badarosk0, Sigma, @Balferian, @tumemmac, @teededung, @attackjom, @Felleonel and @mrjnumber1!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Aleos 4 năm trước cách đây
mục cha
commit
36195d157d

+ 36 - 18
db/re/item_db.txt

@@ -4289,23 +4289,23 @@
 6186,Monkey_Wrench,Monkey Wrench,3,500,,10,,,,,,,,,,,,,{},{},{}
 6187,Blank_Card,Blank Card,3,20,,10,,,,,,,,,,,,,{},{},{}
 6188,Slot_Coupon,Slotting Advertisement,3,20,,10,,,,,,,,,,,,,{},{},{}
-6189,Magic_Book_FB,Spell Book (Fire Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
-6190,Magic_Book_CB,Spell Book (Cold Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
-6191,Magic_Book_LB,Spell Book (Lightening Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
-6192,Magic_Book_SG,Spell Book (Storm Gust),3,0,,0,,,,,,,,,,,,,{},{},{}
-6193,Magic_Book_LOV,Spell Book (Lord Of Vermilion),3,0,,0,,,,,,,,,,,,,{},{},{}
-6194,Magic_Book_MS,Spell Book (Meteor Storm),3,0,,0,,,,,,,,,,,,,{},{},{}
-6195,Magic_Book_CM,Spell Book (Comet),3,0,,0,,,,,,,,,,,,,{},{},{}
-6196,Magic_Book_TV,Spell Book (Tetra Vortex),3,0,,0,,,,,,,,,,,,,{},{},{}
-6197,Magic_Book_TS,Spell Book (Thunder Storm),3,0,,0,,,,,,,,,,,,,{},{},{}
-6198,Magic_Book_JT,Spell Book (Jupitel Thunder),3,0,,0,,,,,,,,,,,,,{},{},{}
-6199,Magic_Book_WB,Spell Book (Water Ball),3,0,,0,,,,,,,,,,,,,{},{},{}
-6200,Magic_Book_HD,Spell Book (Heaven's Drive),3,0,,0,,,,,,,,,,,,,{},{},{}
-6201,Magic_Book_ES,Spell Book (Earth Spike),3,0,,0,,,,,,,,,,,,,{},{},{}
-6202,Magic_Book_ES_,Spell Book (Earth Strain),3,0,,0,,,,,,,,,,,,,{},{},{}
-6203,Magic_Book_CL,Spell Book (Chain Lightning),3,0,,0,,,,,,,,,,,,,{},{},{}
-6204,Magic_Book_CR,Spell Book (Crimson Rock),3,0,,0,,,,,,,,,,,,,{},{},{}
-6205,Magic_Book_DL,Spell Book (Drain Life),3,0,,0,,,,,,,,,,,,,{},{},{}
+6189,Magic_Book_FB,Old Spell Book (Fire Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
+6190,Magic_Book_CB,Old Spell Book (Cold Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
+6191,Magic_Book_LB,Old Spell Book (Lightening Bolt),3,0,,0,,,,,,,,,,,,,{},{},{}
+6192,Magic_Book_SG,Old Spell Book (Storm Gust),3,0,,0,,,,,,,,,,,,,{},{},{}
+6193,Magic_Book_LOV,Old Spell Book (Lord Of Vermilion),3,0,,0,,,,,,,,,,,,,{},{},{}
+6194,Magic_Book_MS,Old Spell Book (Meteor Storm),3,0,,0,,,,,,,,,,,,,{},{},{}
+6195,Magic_Book_CM,Old Spell Book (Comet),3,0,,0,,,,,,,,,,,,,{},{},{}
+6196,Magic_Book_TV,Old Spell Book (Tetra Vortex),3,0,,0,,,,,,,,,,,,,{},{},{}
+6197,Magic_Book_TS,Old Spell Book (Thunder Storm),3,0,,0,,,,,,,,,,,,,{},{},{}
+6198,Magic_Book_JT,Old Spell Book (Jupitel Thunder),3,0,,0,,,,,,,,,,,,,{},{},{}
+6199,Magic_Book_WB,Old Spell Book (Water Ball),3,0,,0,,,,,,,,,,,,,{},{},{}
+6200,Magic_Book_HD,Old Spell Book (Heaven's Drive),3,0,,0,,,,,,,,,,,,,{},{},{}
+6201,Magic_Book_ES,Old Spell Book (Earth Spike),3,0,,0,,,,,,,,,,,,,{},{},{}
+6202,Magic_Book_ES_,Old Spell Book (Earth Strain),3,0,,0,,,,,,,,,,,,,{},{},{}
+6203,Magic_Book_CL,Old Spell Book (Chain Lightning),3,0,,0,,,,,,,,,,,,,{},{},{}
+6204,Magic_Book_CR,Old Spell Book (Crimson Rock),3,0,,0,,,,,,,,,,,,,{},{},{}
+6205,Magic_Book_DL,Old Spell Book (Drain Life),3,0,,0,,,,,,,,,,,,,{},{},{}
 6206,I_Love_You,I Love You,3,0,,0,,,,,,,,,,,,,{},{},{}
 6207,Thank_You,Thank You,3,0,,0,,,,,,,,,,,,,{},{},{}
 6208,I_Respect_You,I Respect You,3,0,,0,,,,,,,,,,,,,{},{},{}
@@ -13668,15 +13668,33 @@
 32351,Estal,Estal,5,20,,700,195,,1,2,0x00040000,56,2,2,4,170,1,2,{ .@r = getrefine(); bonus2 bSkillCooldown,"GN_SPORE_EXPLOSION",-1000; bonus bBaseAtk,4*.@r; if (.@r>=11) .@val = 50; else if (.@r>=9) .@val = 30; bonus2 bSkillAtk,"GN_SPORE_EXPLOSION",.@val; },{},{}
 
 //100052,Enchant_Stone_Box19,Costume Enchantment Stone Box 19,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Enchant_Stone_Box19); },{},{}
+
+//===================================================================
+// New Warlock Spell Books
+//===================================================================
+100065,WL_MB_SG,Spell Book (Storm Gust),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",1; },{},{}
+100066,WL_MB_LOV,Spell Book (Lord of Vermilion),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",2; },{},{}
+100067,WL_MB_MS,Spell Book (Meteor Storm),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",3; },{},{}
+100068,WL_MB_DL,Spell Book (Drain Life),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",4; },{},{}
+100069,WL_MB_JF,Spell Book (Jack Frost),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",5; },{},{}
+100070,WL_MB_ES,Spell Book (Earth Strain),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",6; },{},{}
+100071,WL_MB_CR,Spell Book (Crimson Rock),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",7; },{},{}
+100072,WL_MB_CL,Spell Book (Chain Lightning),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",8; },{},{}
+100073,WL_MB_CM,Spell Book (Comet),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",9; },{},{}
+100074,WL_MB_TV,Spell Book (Tetra Vortex),11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_READING_SB_READING",10; },{},{}
+
 //100202,Enchant_Stone_Box20,Costume Enchantment Stone Box 20,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Enchant_Stone_Box20); },{},{}
+
 //100231,Ref_T_Potion,Golden X,0,10,,30,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_REF_T_POTION,30000,0; },{},{}
 //100232,Add_Atk_Potion,Red Herb Activator,0,10,,30,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_ADD_ATK_DAMAGE,500000,15; },{},{}
 //100233,Add_Matk_Potion,Blue Herb Activator,0,10,,30,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_ADD_MATK_DAMAGE,500000,15; },{},{}
+
 //100314,Enchant_Stone_Box21,Costume Enchantment Stone Box 21,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Enchant_Stone_Box21); },{},{}
 // Costumes
+//400020,C_BeachBall,Costume Beachball,4,0,,0,,,,0,0xFFFFFFFF,63,2,1024,,1,0,1918,{},{},{}
 //440000,C_SharkHead,Costume Shark Hat,4,0,,0,,,,0,0xFFFFFFFF,63,2,5120,,1,0,1919,{},{},{}
 //440002,C_Happy_Cat_TW,Costume Happy Cat,4,0,,0,,,,0,0xFFFFFFFF,63,2,7168,,1,0,1980,{},{},{}
-//400020,C_BeachBall,Costume Beachball,4,0,,0,,,,0,0xFFFFFFFF,63,2,1024,,1,0,1918,{},{},{}
+
 //1100003,Concentrated_R_P,Concentrated Red Potion,0,10,,2,,,,,0xFFFFFFFF,63,2,,,120,,,{ itemheal rand(655,675),0; },{},{}
 //1100004,Concentrated_B_P,Concentrated Blue Potion,0,10,,2,,,,,0xFFFFFFFF,63,2,,,120,,,{ itemheal 0,rand(340,360); },{},{}
 //1100005,Concentrated_G_P,Concentrated Gold Potion,0,10,,2,,,,,0xFFFFFFFF,63,2,,,180,,,{ itemheal rand(2730,2750),0; },{},{}

+ 10 - 0
db/re/item_flag.txt

@@ -1785,3 +1785,13 @@
 12622,32 //Boarding_Halter
 12887,32 //C_Wing_Of_Fly
 22508,32 //Para_Team_Mark_
+//100065,32 //WL_MB_SG
+//100066,32 //WL_MB_LOV
+//100067,32 //WL_MB_MS
+//100068,32 //WL_MB_DL
+//100069,32 //WL_MB_JF
+//100070,32 //WL_MB_ES
+//100071,32 //WL_MB_CR
+//100072,32 //WL_MB_CL
+//100073,32 //WL_MB_CM
+//100074,32 //WL_MB_TV

+ 91 - 120
db/re/skill_db.yml

@@ -9959,25 +9959,25 @@ Body:
     Requires:
       SpCost:
         - Level: 1
-          Amount: 14
+          Amount: 35
         - Level: 2
-          Amount: 18
+          Amount: 40
         - Level: 3
-          Amount: 22
+          Amount: 45
         - Level: 4
-          Amount: 26
+          Amount: 50
         - Level: 5
-          Amount: 30
+          Amount: 55
         - Level: 6
-          Amount: 34
+          Amount: 60
         - Level: 7
-          Amount: 38
+          Amount: 65
         - Level: 8
-          Amount: 42
+          Amount: 70
         - Level: 9
-          Amount: 46
+          Amount: 75
         - Level: 10
-          Amount: 50
+          Amount: 80
   - Id: 367
     Name: PA_PRESSURE
     Description: Gloria Domini
@@ -18089,25 +18089,36 @@ Body:
     Description: Frosty Misty
     MaxLevel: 5
     Type: Magic
-    TargetType: Self
+    TargetType: Ground
     DamageFlags:
       Splash: true
     Flags:
       AlterRangeRadius: true
+    Range: 11
     Hit: Multi_Hit
     HitCount:
       - Level: 1
-        Count: -3
+        Count: 1
       - Level: 2
-        Count: -4
+        Count: 2
       - Level: 3
-        Count: -5
+        Count: 3
       - Level: 4
-        Count: -6
+        Count: 4
       - Level: 5
-        Count: -7
+        Count: 5
     Element: Water
-    SplashArea: 9
+    SplashArea:
+      - Level: 1
+        Area: 3
+      - Level: 2
+        Area: 3
+      - Level: 3
+        Area: 4
+      - Level: 4
+        Area: 4
+      - Level: 5
+        Area: 5
     CopyFlags:
       Skill:
         Reproduce: true
@@ -18125,6 +18136,7 @@ Body:
         Time: 4000
     AfterCastActDelay: 1000
     Duration1: 40000
+    Duration2: 10000
     Cooldown: 4000
     FixedCastTime: 500
     Requires:
@@ -18144,23 +18156,24 @@ Body:
     Description: Jack Frost
     MaxLevel: 5
     Type: Magic
-    TargetType: Self
+    TargetType: Attack
     DamageFlags:
       Splash: true
+    Range: 11
     Hit: Multi_Hit
     HitCount: -5
     Element: Water
     SplashArea:
       - Level: 1
-        Area: 5
+        Area: 3
       - Level: 2
-        Area: 6
+        Area: 3
       - Level: 3
-        Area: 7
+        Area: 4
       - Level: 4
-        Area: 8
+        Area: 4
       - Level: 5
-        Area: 9
+        Area: 5
     CopyFlags:
       Skill:
         Reproduce: true
@@ -18188,6 +18201,7 @@ Body:
         Time: 27500
       - Level: 5
         Time: 32500
+    Cooldown: 4000
     FixedCastTime: 1000
     Requires:
       SpCost:
@@ -18450,7 +18464,7 @@ Body:
         Reproduce: true
     CastCancel: true
     CastTime: 5000
-    AfterCastActDelay: 2000
+    AfterCastActDelay: 500
     Duration1: 5000
     Cooldown: 5000
     FixedCastTime: 1000
@@ -18472,32 +18486,46 @@ Body:
     MaxLevel: 5
     Type: Magic
     TargetType: Attack
+    DamageFlags:
+      Splash: true
     Flags:
       AlterRangeRadius: true
     Range: 11
     Hit: Single
     HitCount: 1
     Element: Fire
+    SplashArea:
+      - Level: 1
+        Area: 1
+      - Level: 2
+        Area: 1
+      - Level: 3
+        Area: 1
+      - Level: 4
+        Area: 2
+      - Level: 5
+        Area: 2
     CopyFlags:
       Skill:
         Reproduce: true
     CastCancel: true
     CastTime: 3000
-    AfterCastActDelay: 1000
+    AfterCastActDelay: 500
     Duration1: 15000
+    Cooldown: 3000
     FixedCastTime: 1000
     Requires:
       SpCost:
         - Level: 1
-          Amount: 35
+          Amount: 64
         - Level: 2
-          Amount: 40
+          Amount: 70
         - Level: 3
-          Amount: 45
+          Amount: 76
         - Level: 4
-          Amount: 50
+          Amount: 82
         - Level: 5
-          Amount: 55
+          Amount: 88
   - Id: 2213
     Name: WL_COMET
     Description: Comet
@@ -18510,8 +18538,8 @@ Body:
       AlterRangeRadius: true
     Range: 11
     Hit: Multi_Hit
-    HitCount: -20
-    SplashArea: 9
+    HitCount: -10
+    SplashArea: 6
     Knockback: 2
     CopyFlags:
       Skill:
@@ -18519,45 +18547,32 @@ Body:
     CastCancel: true
     CastTime:
       - Level: 1
-        Time: 10000
+        Time: 6000
       - Level: 2
-        Time: 11000
+        Time: 7000
       - Level: 3
-        Time: 12000
+        Time: 8000
       - Level: 4
-        Time: 13000
+        Time: 9000
       - Level: 5
-        Time: 14000
-    AfterCastActDelay: 2000
+        Time: 10000
+    AfterCastActDelay: 1500
     Duration1: 100
     Duration2: 42000
-    Cooldown: 60000
-    FixedCastTime:
-      - Level: 1
-        Time: 1000
-      - Level: 2
-        Time: 1500
-      - Level: 3
-        Time: 2000
-      - Level: 4
-        Time: 2500
-      - Level: 5
-        Time: 3000
+    Cooldown: 20000
+    FixedCastTime: 2000
     Requires:
       SpCost:
         - Level: 1
-          Amount: 480
+          Amount: 70
         - Level: 2
-          Amount: 560
+          Amount: 90
         - Level: 3
-          Amount: 640
+          Amount: 110
         - Level: 4
-          Amount: 720
+          Amount: 130
         - Level: 5
-          Amount: 800
-      ItemCost:
-        - Item: Red_Gemstone
-          Amount: 2
+          Amount: 150
     Unit:
       Id: Dummyskill
       Range: 9
@@ -18661,7 +18676,7 @@ Body:
         Time: 5000
       - Level: 5
         Time: 6000
-    AfterCastActDelay: 1000
+    AfterCastActDelay: 500
     Duration1: 100
     Duration2:
       - Level: 1
@@ -18674,7 +18689,7 @@ Body:
         Time: 120000
       - Level: 5
         Time: 135000
-    Cooldown: 10000
+    Cooldown: 7000
     FixedCastTime: 2000
     Requires:
       SpCost:
@@ -18842,7 +18857,7 @@ Body:
   - Id: 2222
     Name: WL_SUMMONFB
     Description: Summon Fire Ball
-    MaxLevel: 5
+    MaxLevel: 2
     Type: Magic
     TargetType: Self
     DamageFlags:
@@ -18855,17 +18870,7 @@ Body:
         Reproduce: true
     CastCancel: true
     CastTime: 2000
-    Duration1:
-      - Level: 1
-        Time: 120000
-      - Level: 2
-        Time: 160000
-      - Level: 3
-        Time: 200000
-      - Level: 4
-        Time: 240000
-      - Level: 5
-        Time: 280000
+    Duration1: 280000
     FixedCastTime: -1
     Requires:
       SpCost:
@@ -18882,7 +18887,7 @@ Body:
   - Id: 2223
     Name: WL_SUMMONBL
     Description: Summon Lightning Ball
-    MaxLevel: 5
+    MaxLevel: 2
     Type: Magic
     TargetType: Self
     DamageFlags:
@@ -18895,17 +18900,7 @@ Body:
         Reproduce: true
     CastCancel: true
     CastTime: 2000
-    Duration1:
-      - Level: 1
-        Time: 120000
-      - Level: 2
-        Time: 160000
-      - Level: 3
-        Time: 200000
-      - Level: 4
-        Time: 240000
-      - Level: 5
-        Time: 280000
+    Duration1: 280000
     FixedCastTime: -1
     Requires:
       SpCost:
@@ -18922,7 +18917,7 @@ Body:
   - Id: 2224
     Name: WL_SUMMONWB
     Description: Summon Water Ball
-    MaxLevel: 5
+    MaxLevel: 2
     Type: Magic
     TargetType: Self
     DamageFlags:
@@ -18935,17 +18930,7 @@ Body:
         Reproduce: true
     CastCancel: true
     CastTime: 2000
-    Duration1:
-      - Level: 1
-        Time: 120000
-      - Level: 2
-        Time: 160000
-      - Level: 3
-        Time: 200000
-      - Level: 4
-        Time: 240000
-      - Level: 5
-        Time: 280000
+    Duration1: 280000
     FixedCastTime: -1
     Requires:
       SpCost:
@@ -19026,7 +19011,7 @@ Body:
   - Id: 2229
     Name: WL_SUMMONSTONE
     Description: Summon Stone
-    MaxLevel: 5
+    MaxLevel: 2
     Type: Magic
     TargetType: Self
     DamageFlags:
@@ -19039,17 +19024,7 @@ Body:
         Reproduce: true
     CastCancel: true
     CastTime: 2000
-    Duration1:
-      - Level: 1
-        Time: 120000
-      - Level: 2
-        Time: 160000
-      - Level: 3
-        Time: 200000
-      - Level: 4
-        Time: 240000
-      - Level: 5
-        Time: 280000
+    Duration1: 280000
     FixedCastTime: -1
     Requires:
       SpCost:
@@ -19085,19 +19060,7 @@ Body:
     Name: WL_READING_SB
     Description: Reading Spellbook
     MaxLevel: 1
-    Type: Magic
-    TargetType: Self
-    DamageFlags:
-      NoDamage: true
-    Hit: Single
-    HitCount: 1
-    CastCancel: true
-    CastTime: 5000
-    AfterCastActDelay: 500
     Duration1: 30000
-    FixedCastTime: 1000
-    Requires:
-      SpCost: 40
   - Id: 2232
     Name: WL_FREEZE_SP
     Description: Freeze Spell
@@ -33511,6 +33474,14 @@ Body:
     Name: NV_TRANSCENDENCE
     Description: Transcendence
     MaxLevel: 5
+  - Id: 5078
+    Name: WL_READING_SB_READING
+    Description: Reading Spellbook
+    MaxLevel: 10
+    TargetType: Self
+    CastTime: 5000
+    AfterCastActDelay: 500
+    FixedCastTime: 1000
   - Id: 8001
     Name: HLIF_HEAL
     Description: Healing Touch

+ 12 - 12
db/re/skill_tree.txt

@@ -2492,10 +2492,10 @@
 4055,2214,5,2223,1,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning#
 4055,2216,5,2207,2,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain#
 4055,2217,10,2204,5,2212,5,2214,5,2216,5,0,0 //WL_TETRAVORTEX#Tetra Vortex#
-4055,2222,5,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
-4055,2223,5,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
-4055,2224,5,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
-4055,2229,5,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
+4055,2222,2,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
+4055,2223,2,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
+4055,2224,2,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
+4055,2229,2,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
 4055,2230,2,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release#
 4055,2231,1,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook#
 4055,2232,10,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell#
@@ -2833,10 +2833,10 @@
 4061,2214,5,2223,1,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning#
 4061,2216,5,2207,2,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain#
 4061,2217,10,2204,5,2212,5,2214,5,2216,5,0,0 //WL_TETRAVORTEX#Tetra Vortex#
-4061,2222,5,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
-4061,2223,5,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
-4061,2224,5,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
-4061,2229,5,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
+4061,2222,2,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
+4061,2223,2,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
+4061,2224,2,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
+4061,2229,2,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
 4061,2230,2,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release#
 4061,2231,1,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook#
 4061,2232,10,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell#
@@ -4500,10 +4500,10 @@
 4097,2214,5,2223,1,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning#
 4097,2216,5,2207,2,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain#
 4097,2217,10,2204,5,2212,5,2214,5,2216,5,0,0 //WL_TETRAVORTEX#Tetra Vortex#
-4097,2222,5,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
-4097,2223,5,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
-4097,2224,5,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
-4097,2229,5,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
+4097,2222,2,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball#
+4097,2223,2,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball#
+4097,2224,2,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball#
+4097,2229,2,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone#
 4097,2230,2,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release#
 4097,2231,1,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook#
 4097,2232,10,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell#

+ 12 - 33
db/re/spellbook_db.yml

@@ -32,54 +32,33 @@ Header:
   Version: 1
 
 Body:
-  - Skill: MG_COLDBOLT
-    Book: Magic_Book_CB
-    PreservePoints: 7
-  - Skill: MG_FIREBOLT
-    Book: Magic_Book_FB
-    PreservePoints: 7
-  - Skill: MG_LIGHTNINGBOLT
-    Book: Magic_Book_LB
-    PreservePoints: 7
-  - Skill: MG_THUNDERSTORM
-    Book: Magic_Book_TS
-    PreservePoints: 9
   - Skill: WZ_METEOR
-    Book: Magic_Book_MS
+    Book: WL_MB_MS
     PreservePoints: 10
-  - Skill: WZ_JUPITEL
-    Book: Magic_Book_JT
-    PreservePoints: 9
   - Skill: WZ_VERMILION
-    Book: Magic_Book_LOV
+    Book: WL_MB_LOV
     PreservePoints: 10
-  - Skill: WZ_WATERBALL
-    Book: Magic_Book_WB
-    PreservePoints: 9
   - Skill: WZ_STORMGUST
-    Book: Magic_Book_SG
+    Book: WL_MB_SG
+    PreservePoints: 10
+  - Skill: WL_JACKFROST
+    Book: WL_MB_JF
     PreservePoints: 10
-  - Skill: WZ_EARTHSPIKE
-    Book: Magic_Book_ES
-    PreservePoints: 8
-  - Skill: WZ_HEAVENDRIVE
-    Book: Magic_Book_HD
-    PreservePoints: 9
   - Skill: WL_DRAINLIFE
-    Book: Magic_Book_DL
+    Book: WL_MB_DL
     PreservePoints: 8
   - Skill: WL_CRIMSONROCK
-    Book: Magic_Book_CR
+    Book: WL_MB_CR
     PreservePoints: 12
   - Skill: WL_COMET
-    Book: Magic_Book_CM
+    Book: WL_MB_CM
     PreservePoints: 22
   - Skill: WL_CHAINLIGHTNING
-    Book: Magic_Book_CL
+    Book: WL_MB_CL
     PreservePoints: 12
   - Skill: WL_EARTHSTRAIN
-    Book: Magic_Book_ES_
+    Book: WL_MB_ES
     PreservePoints: 12
   - Skill: WL_TETRAVORTEX
-    Book: Magic_Book_TV
+    Book: WL_MB_TV
     PreservePoints: 22

+ 11 - 0
sql-files/upgrades/upgrade_20200505.sql

@@ -0,0 +1,11 @@
+-- WL_SUMMONFB
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + (`s`.lv - 2), `s`.lv = 2 WHERE `s`.id = 2222 AND `s`.lv > 2 AND `c`.char_id = `s`.char_id;
+
+-- WL_SUMMONBL
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + (`s`.lv - 2), `s`.lv = 2 WHERE `s`.id = 2223 AND `s`.lv > 2 AND `c`.char_id = `s`.char_id;
+
+-- WL_SUMMONWB
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + (`s`.lv - 2), `s`.lv = 2 WHERE `s`.id = 2224 AND `s`.lv > 2 AND `c`.char_id = `s`.char_id;
+
+-- WL_SUMMONSTONE
+UPDATE `char` c, `skill` s SET `c`.skill_point = `c`.skill_point + (`s`.lv - 2), `s`.lv = 2 WHERE `s`.id = 2229 AND `s`.lv > 2 AND `c`.char_id = `s`.char_id;

+ 28 - 40
src/map/battle.cpp

@@ -601,6 +601,13 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d
 				}
 				break;
 		}
+
+		if (tsc->data[SC_MAGIC_POISON])
+#ifdef RENEWAL
+			ratio += 50;
+#else
+			damage += (int64)(damage * 50 / 100);
+#endif
 	}
 
 	if (battle_config.attr_recover == 0 && ratio < 0)
@@ -6112,8 +6119,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 				s_ele = ELE_HOLY;
 			break;
 		case WL_HELLINFERNO:
-			if (mflag&ELE_DARK)
+			if (mflag == ELE_DARK) {
 				s_ele = ELE_DARK;
+				ad.div_ = 3;
+			}
 			break;
 		case WM_REVERBERATION:
 			if (sd)
@@ -6448,14 +6457,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 						skillratio += 300 + 40 * skill_lv;
 						break;
 					case WL_SOULEXPANSION:
-						skillratio += -100 + (skill_lv + 4) * 100 + status_get_int(src);
+						skillratio += -100 + 750 + skill_lv * 150 + sstatus->int_;
 						RE_LVL_DMOD(100);
 						break;
 					case WL_FROSTMISTY:
-						skillratio += 100 + 100 * skill_lv;
+						skillratio += -100 + 200 + 100 * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
-					case WL_JACKFROST:
 					case NPC_JACKFROST:
 						if (tsc && tsc->data[SC_FREEZING]) {
 							skillratio += 900 + 300 * skill_lv;
@@ -6465,50 +6473,30 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 							RE_LVL_DMOD(150);
 						}
 						break;
+					case WL_JACKFROST:
+						if (tsc && tsc->data[SC_MISTY_FROST])
+							skillratio += -100 + 1200 + 600 * skill_lv;
+						else
+							skillratio += -100 + 1000 + 300 * skill_lv;
+						RE_LVL_DMOD(100);
+						break;
 					case WL_DRAINLIFE:
-						skillratio += -100 + 200 * skill_lv + status_get_int(src);
+						skillratio += -100 + 200 * skill_lv + sstatus->int_;
 						RE_LVL_DMOD(100);
 						break;
 					case WL_CRIMSONROCK:
-						skillratio += 1200 + 300 * skill_lv;
+						skillratio += -100 + 700 + 600 * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
 					case WL_HELLINFERNO:
-						skillratio += -100 + 300 * skill_lv;
+						skillratio += -100 + 400 * skill_lv;
+						if (mflag == ELE_DARK)
+							skillratio += 200;
 						RE_LVL_DMOD(100);
-						// Shadow: MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) x 4/5 }] %
-						// Fire : MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) /5 }] %
-						if (mflag&ELE_DARK)
-							skillratio *= 4;
-						skillratio /= 5;
 						break;
 					case WL_COMET:
-						i = (sc ? distance_xy(target->x, target->y, sc->comet_x, sc->comet_y) : 8);
-						if (i <= 3)
-							skillratio += 2400 + 500 * skill_lv; // 7 x 7 cell
-						else if (i <= 5)
-							skillratio += 1900 + 500 * skill_lv; // 11 x 11 cell
-						else if (i <= 7)
-							skillratio += 1400 + 500 * skill_lv; // 15 x 15 cell
-						else
-							skillratio += 900 + 500 * skill_lv; // 19 x 19 cell
-
-						if (sd && sd->status.party_id) {
-							struct map_session_data* psd;
-							int p_sd[MAX_PARTY], c;
-
-							c = 0;
-							memset(p_sd, 0, sizeof(p_sd));
-							party_foreachsamemap(skill_check_condition_char_sub, sd, 3, &sd->bl, &c, &p_sd, skill_id);
-							c = (c > 1 ? rnd()%c : 0);
-
-							if( (psd = map_id2sd(p_sd[c])) && pc_checkskill(psd,WL_COMET) > 0 ){
-								skillratio = skill_lv * 400; //MATK [{( Skill Level x 400 ) x ( Caster's Base Level / 120 )} + 2500 ] %
-								RE_LVL_DMOD(120);
-								skillratio += 2500;
-								status_zap(&psd->bl, 0, skill_get_sp(skill_id, skill_lv) / 2);
-							}
-						}
+						skillratio += -100 + 2500 + 500 * skill_lv;
+						RE_LVL_DMOD(100);
 						break;
 					case WL_CHAINLIGHTNING_ATK:
 						skillratio += 400 + 100 * skill_lv;
@@ -6517,7 +6505,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 							skillratio += 100 * mflag;
 						break;
 					case WL_EARTHSTRAIN:
-						skillratio += 1900 + 100 * skill_lv;
+						skillratio += -100 + 1000 + 600 * skill_lv;
 						RE_LVL_DMOD(100);
 						break;
 					case WL_TETRAVORTEX_FIRE:
@@ -6534,7 +6522,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
 					case WL_SUMMON_ATK_WIND:
 					case WL_SUMMON_ATK_GROUND:
 						skillratio += -100 + (1 + skill_lv) / 2 * (status_get_lv(src) + (sd ? sd->status.job_level : 0));
-						RE_LVL_DMOD(100);
+						RE_LVL_DMOD(100); // ! TODO: Confirm new formula
 						break;
 					case LG_RAYOFGENESIS:
 						skillratio += -100 + 200 * skill_lv;

+ 0 - 39
src/map/clif.cpp

@@ -13056,9 +13056,6 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) {
 		case SA_CREATECON:
 			skill_produce_mix(sd,SA_CREATECON,p->itemId,0,0,0,1,-1);
 			break;
-		case WL_READING_SB:
-			skill_spellbook(sd,p->itemId);
-			break;
 		case GC_POISONINGWEAPON:
 			skill_poisoningweapon(sd,p->itemId);
 			break;
@@ -18957,43 +18954,7 @@ void clif_millenniumshield(struct block_list *bl, short shields) {
 	clif_send(buf,packet_len(0x440),bl,AREA);
 #endif
 }
-/**
- * Warlock
- **/
-/*==========================================
- * Spellbook list [LimitLine/3CeAM]
- *------------------------------------------*/
-void clif_spellbook_list( struct map_session_data *sd ){
-	nullpo_retv( sd );
-
-	int fd = sd->fd;
-
-	if( !session_isActive( fd ) ){
-		return;
-	}
-
-	WFIFOHEAD( fd, sizeof( struct PACKET_ZC_MAKINGARROW_LIST ) + MAX_INVENTORY * sizeof( struct PACKET_ZC_MAKINGARROW_LIST_sub ) );
-	struct PACKET_ZC_MAKINGARROW_LIST *p = (struct PACKET_ZC_MAKINGARROW_LIST *)WFIFOP( fd, 0 );
-	p->packetType = HEADER_ZC_MAKINGARROW_LIST;
-
-	int count = 0;
-	for( int i = 0; i < MAX_INVENTORY; i++ ){
-		if( reading_spellbook_db.findBook( sd->inventory.u.items_inventory[i].nameid ) ){
-			p->items[count].itemId = client_nameid( sd->inventory.u.items_inventory[i].nameid );
-			count++;
-		}
-	}
 
-	if( count > 0 ){
-		p->packetLength = sizeof( struct PACKET_ZC_MAKINGARROW_LIST ) + count * sizeof( struct PACKET_ZC_MAKINGARROW_LIST_sub );
-		WFIFOSET( fd, p->packetLength );
-		sd->menuskill_id = WL_READING_SB;
-		sd->menuskill_val = count;
-	}else{
-		status_change_end( &sd->bl, SC_STOP, INVALID_TIMER );
-		clif_skill_fail( sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK, 0 );
-	}
-}
 /**
  * Mechanic
  **/

+ 0 - 2
src/map/clif.hpp

@@ -1050,8 +1050,6 @@ void clif_elementalconverter_list(struct map_session_data *sd);
 
 void clif_millenniumshield(struct block_list *bl, short shields);
 
-void clif_spellbook_list(struct map_session_data *sd);
-
 void clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, short x, short y);
 
 void clif_poison_list(struct map_session_data *sd, uint16 skill_lv);

+ 1 - 0
src/map/itemdb.hpp

@@ -113,6 +113,7 @@ enum item_itemid : t_itemid
 	ITEMID_WOB_RACHEL					= 14584,
 	ITEMID_WOB_LOCAL					= 14585,
 	ITEMID_SIEGE_TELEPORT_SCROLL		= 14591,
+	ITEMID_WL_MB_SG						= 100065,
 };
 
 ///Rune Knight

+ 170 - 206
src/map/skill.cpp

@@ -1704,20 +1704,12 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
 	case AB_ADORAMUS:
 		sc_start(src,bl, SC_ADORAMUS, skill_lv * 4 + (sd ? sd->status.job_level : 50) / 2, skill_lv, skill_get_time2(skill_id, skill_lv));
 		break;
-	case WL_CRIMSONROCK:
-		sc_start(src,bl, SC_STUN, 40, skill_lv, skill_get_time(skill_id, skill_lv));
-		break;
 	case WL_COMET:
+		sc_start(src, bl, status_skill2sc(skill_id), 100, skill_lv, 20000);
+		break;
 	case NPC_COMET:
 		sc_start4(src,bl,SC_BURNING,100,skill_lv,1000,src->id,0,skill_get_time(skill_id,skill_lv));
 		break;
-	case WL_EARTHSTRAIN:
-		if (dmg_lv != ATK_DEF) // Only strip if we make a successful hit.
-			break;
-
-		skill_strip_equip(src, bl, skill_id, skill_lv);
-		break;
-	case WL_JACKFROST:
 	case NPC_JACKFROST:
 		sc_start(src,bl,SC_FREEZE,200,skill_lv,skill_get_time(skill_id,skill_lv));
 		break;
@@ -2801,13 +2793,6 @@ bool skill_strip_equip(struct block_list *src, struct block_list *target, uint16
 		case SC_STRIPACCESSARY:
 			location = EQP_ACC;
 			break;
-		case WL_EARTHSTRAIN:
-			location = EQP_SHIELD|EQP_ARMOR|EQP_HELM;
-			if (skill_lv >= 4)
-				location |= EQP_WEAPON;
-			if (skill_lv >= 5)
-				location |= EQP_ACC;
-			break;
 	}
 
 	for (uint8 i = 0; i < ARRAYLENGTH(pos); i++) {
@@ -3479,10 +3464,6 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 	dmg_type = (skill_id == 0) ? DMG_SPLASH : skill_get_hit(skill_id);
 
 	switch( skill_id ) {
-		case WL_HELLINFERNO:
-			if (dmg.dmg_lv == ATK_DEF && !(flag&ELE_DARK)) // Burning only starts if the fire attack successfully lands
-				sc_start4(src, bl, SC_BURNING, 55 + 5 * skill_lv, skill_lv, 1000, src->id, 0, skill_get_time(skill_id, skill_lv));
-			break;
 		case SC_TRIANGLESHOT:
 			if( rnd()%100 > (1 + skill_lv) )
 				dmg.blewcount = 0;
@@ -3551,7 +3532,6 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
 			else // the central target doesn't display an animation
 				dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, DMG_SPLASH); // needs -2(!) as skill level
 			break;
-		case WL_HELLINFERNO:
 		case SR_EARTHSHAKER:
 			dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skill_id,-2,DMG_SINGLE);
 			break;
@@ -4337,11 +4317,7 @@ static TIMER_FUNC(skill_timerskill){
 							}
 							if (j) {
 								i = applyeffects[rnd()%j];
-								status_change_start(src, target, static_cast<sc_type>(i), 10000, skl->skill_lv,
-									(i == SC_BURNING ? 1000 : (i == SC_BLEEDING ? src->id : 0)),
-									(i == SC_BURNING ? src->id : 0), 0,
-									(i == SC_BURNING ? 15000 : (i == SC_FREEZING ? 40000 :
-									(i == SC_BLEEDING ? 120000 : 5000))), SCSTART_NONE);
+								sc_start(src, target, static_cast<sc_type>(i), 100, skl->skill_lv, (i == SC_BURNING ? 18000 : (i == SC_FREEZING ? 27000 : (i == SC_BLEEDING ? 108000 : 4500))));
 							}
 						}
 					}
@@ -5724,86 +5700,99 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 		break;
 
 	case WL_TETRAVORTEX:
-		if( sc ) { // No SC? No spheres
-			int spheres[5] = { 0, 0, 0, 0, 0 },
-				positions[5] = {-1,-1,-1,-1,-1 },
-				i, j = 0, k, subskill = 0;
-
-			for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
-				if( sc->data[i] ) {
-					spheres[j] = i;
-					positions[j] = sc->data[i]->val2;
-					j++;
-				}
+		if (sd == nullptr) { // Monster usage
+			uint8 i = 0;
+			const static std::vector<std::vector<uint16>> tetra_skills = { { WL_TETRAVORTEX_FIRE, 1 },
+																		   { WL_TETRAVORTEX_WIND, 4 },
+																		   { WL_TETRAVORTEX_WATER, 2 },
+																		   { WL_TETRAVORTEX_GROUND, 8 } };
+
+			for (const auto &skill : tetra_skills) {
+				if (skill_lv > 5) {
+					skill_area_temp[0] = i;
+					skill_area_temp[1] = skill[1];
+					map_foreachinallrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill[0], skill_lv, tick, flag | BCT_ENEMY, skill_castend_damage_id);
+				} else
+					skill_addtimerskill(src, tick + i * 200, bl->id, skill[1], 0, skill[0], skill_lv, i, flag);
+				i++;
+			}
+		} else if (sc) { // No SC? No spheres
+			int i, k = 0;
 
-			// Sphere Sort, this time from new to old
-			for( i = 0; i <= j - 2; i++ )
-				for( k = i + 1; k <= j - 1; k++ )
-					if( positions[i] < positions[k] ) {
-						SWAP(positions[i],positions[k]);
-						SWAP(spheres[i],spheres[k]);
-					}
+			if (sc->data[SC_SPHERE_5]) // If 5 spheres, remove last one (based on reverse order) and only do 4 actions (Official behavior)
+				status_change_end(src, SC_SPHERE_1, INVALID_TIMER);
 
-			if(j == 5) { // If 5 spheres, remove last one and only do 4 actions (Official behavior)
-				status_change_end(src, static_cast<sc_type>(spheres[4]), INVALID_TIMER);
-				j = 4;
-			}
+			for (i = SC_SPHERE_5; i >= SC_SPHERE_1; i--) { // Loop should always be 4 for regular players, but unconditional_skill could be less
+				if (sc->data[static_cast<sc_type>(i)] == nullptr)
+					continue;
 
-			k = 0;
-			for( i = 0; i < j; i++ ) { // Loop should always be 4 for regular players, but unconditional_skill could be less
-				switch( sc->data[spheres[i]]->val1 ) {
-					case WLS_FIRE:  subskill = WL_TETRAVORTEX_FIRE; k |= 1; break;
-					case WLS_WIND:  subskill = WL_TETRAVORTEX_WIND; k |= 4; break;
-					case WLS_WATER: subskill = WL_TETRAVORTEX_WATER; k |= 2; break;
-					case WLS_STONE: subskill = WL_TETRAVORTEX_GROUND; k |= 8; break;
+				uint16 subskill = 0;
+
+				switch (sc->data[static_cast<sc_type>(i)]->val1) {
+					case WLS_FIRE:
+						subskill = WL_TETRAVORTEX_FIRE;
+						k |= 1;
+						break;
+					case WLS_WIND:
+						subskill = WL_TETRAVORTEX_WIND;
+						k |= 4;
+						break;
+					case WLS_WATER:
+						subskill = WL_TETRAVORTEX_WATER;
+						k |= 2;
+						break;
+					case WLS_STONE:
+						subskill = WL_TETRAVORTEX_GROUND;
+						k |= 8;
+						break;
 				}
 
 				if (skill_lv > 5) {
-					skill_area_temp[0] = i;
+					skill_area_temp[0] = abs(i - SC_SPHERE_5);
 					skill_area_temp[1] = k;
 					map_foreachinallrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, subskill, skill_lv, tick, flag | BCT_ENEMY, skill_castend_damage_id);
 				} else
-					skill_addtimerskill(src, tick + i * 200, bl->id, k, 0, subskill, skill_lv, i, flag);
-				status_change_end(src, static_cast<sc_type>(spheres[i]), INVALID_TIMER);
+					skill_addtimerskill(src, tick + abs(i - SC_SPHERE_5) * 200, bl->id, k, 0, subskill, skill_lv, abs(i - SC_SPHERE_5), flag);
+				status_change_end(src, static_cast<sc_type>(i), INVALID_TIMER);
 			}
 		}
 		break;
 
 	case WL_RELEASE:
-		if( sd )
-		{
+		if (sc == nullptr)
+			break;
+		if (sd) {
 			int i;
 
 			skill_toggle_magicpower(src, skill_id); // No hit will be amplified
-			// Priority is to release SpellBook
-			if( sc && sc->data[SC_FREEZE_SP] )
-			{ // SpellBook
-				uint16 pres_skill_id, pres_skill_lv, point, s = 0;
-				int spell[SC_MAXSPELLBOOK-SC_SPELLBOOK1 + 1];
-				int cooldown;
+			if (skill_lv == 1) { // SpellBook
+				if (sc->data[SC_FREEZE_SP] == nullptr)
+					break;
 
-				for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) // List all available spell to be released
-					if( sc->data[i] ) spell[s++] = i;
+				bool found_spell = false;
 
-				if ( s == 0 )
-					break;
+				for (i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) { // List all available spell to be released
+					if (sc->data[i] != nullptr) {
+						found_spell = true;
+						break;
+					}
+				}
 
-				i = spell[s==1?0:rnd()%s];// Random select of spell to be released.
-				if(sc->data[i] ){// Now extract the data from the preserved spell
-					pres_skill_id = sc->data[i]->val1;
-					pres_skill_lv = sc->data[i]->val2;
-					point = sc->data[i]->val3;
-					status_change_end(src, static_cast<sc_type>(i), INVALID_TIMER);
-				}else //something went wrong :(
+				if (!found_spell)
 					break;
 
+				// Now extract the data from the preserved spell
+				uint16 pres_skill_id = sc->data[i]->val1;
+				uint16 pres_skill_lv = sc->data[i]->val2;
+				uint16 point = sc->data[i]->val3;
+
+				status_change_end(src, static_cast<sc_type>(i), INVALID_TIMER);
+
 				if( sc->data[SC_FREEZE_SP]->val2 > point )
 					sc->data[SC_FREEZE_SP]->val2 -= point;
 				else // Last spell to be released
 					status_change_end(src, SC_FREEZE_SP, INVALID_TIMER);
 
-				if( bl->type != BL_SKILL ) /* skill types will crash the client */
-					clif_skill_nodamage(src, bl, pres_skill_id, pres_skill_lv, 1);
 				if( !skill_check_condition_castbegin(sd, pres_skill_id, pres_skill_lv) )
 					break;
 
@@ -5826,62 +5815,41 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 				sd->ud.canact_tick = i64max(tick + skill_delayfix(src, pres_skill_id, pres_skill_lv), sd->ud.canact_tick);
 				clif_status_change(src, EFST_POSTDELAY, 1, skill_delayfix(src, pres_skill_id, pres_skill_lv), 0, 0, 0);
 
-				cooldown = pc_get_skillcooldown(sd,pres_skill_id, pres_skill_lv);
-				if( cooldown )
-					skill_blockpc_start(sd, pres_skill_id, cooldown);
-			}
-			else
-			{ // Summon Balls
-				int j = 0, k;
-				int spheres[5] = { 0, 0, 0, 0, 0 },
-					positions[5] = {-1,-1,-1,-1,-1 };
-
-				for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
-					if( sc && sc->data[i] )
-					{
-						spheres[j] = i;
-						positions[j] = sc->data[i]->val2;
-						sc->data[i]->val2--; // Prepares for next position
-						j++;
-					}
+				int cooldown = pc_get_skillcooldown(sd,pres_skill_id, pres_skill_lv);
 
-				if( j == 0 )
-				{ // No Spheres
-					clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0);
-					break;
-				}
+				if( cooldown > 0 )
+					skill_blockpc_start(sd, pres_skill_id, cooldown);
+			} else { // Summoned Balls
+				for (i = SC_SPHERE_5; i >= SC_SPHERE_1; i--) {
+					if (sc->data[static_cast<sc_type>(i)] == nullptr)
+						continue;
 
-				// Sphere Sort
-				for( i = 0; i <= j - 2; i++ )
-					for( k = i + 1; k <= j - 1; k++ )
-						if( positions[i] > positions[k] )
-						{
-							SWAP(positions[i],positions[k]);
-							SWAP(spheres[i],spheres[k]);
-						}
+					int skele = WL_RELEASE - 5 + sc->data[static_cast<sc_type>(i)]->val1 - WLS_FIRE; // Convert Ball Element into Skill ATK for balls
 
-				if( skill_lv == 1 ) j = 1; // Limit only to one ball
-				for( i = 0; i < j; i++ )
-				{
-					int skele = WL_RELEASE - 5 + sc->data[spheres[i]]->val1 - WLS_FIRE; // Convert Ball Element into Skill ATK for balls
 					// WL_SUMMON_ATK_FIRE, WL_SUMMON_ATK_WIND, WL_SUMMON_ATK_WATER, WL_SUMMON_ATK_GROUND
-					skill_addtimerskill(src,tick+(t_tick)status_get_adelay(src)*i,bl->id,0,0,skele,sc->data[spheres[i]]->val3,BF_MAGIC,flag|SD_LEVEL);
-					status_change_end(src, static_cast<sc_type>(spheres[i]), INVALID_TIMER); // Eliminate ball
+					skill_addtimerskill(src, tick + (t_tick)status_get_adelay(src) * abs(i - SC_SPHERE_1), bl->id, 0, 0, skele, sc->data[static_cast<sc_type>(i)]->val2, BF_MAGIC, flag | SD_LEVEL);
+					status_change_end(src, static_cast<sc_type>(i), INVALID_TIMER); // Eliminate ball
 				}
-				clif_skill_nodamage(src,bl,skill_id,0,1);
+				clif_skill_nodamage(src, bl, skill_id, 0, 1);
 			}
 		}
 		break;
 	case WL_FROSTMISTY:
 		// Causes Freezing status through walls.
-		sc_start(src,bl,status_skill2sc(skill_id),20+12*skill_lv+(sd ? sd->status.job_level : 50)/5,skill_lv,skill_get_time(skill_id,skill_lv));
+		sc_start(src, bl, status_skill2sc(skill_id), 25 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
+		sc_start(src, bl, SC_MISTY_FROST, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
 		// Doesn't deal damage through non-shootable walls.
 		if( !battle_config.skill_wall_check || (battle_config.skill_wall_check && path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL)) )
 			skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION);
 		break;
 	case WL_HELLINFERNO:
-		skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag);
-		skill_addtimerskill(src,tick + 200,bl->id,0,0,skill_id,skill_lv,BF_MAGIC,flag|ELE_DARK);
+		if (flag & 1) {
+			skill_attack(BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag);
+			skill_addtimerskill(src, tick + 300, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag | ELE_DARK);
+		} else {
+			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
+		}
 		break;
 	case RA_WUGSTRIKE:
 		if( sd && pc_isridingwug(sd) ){
@@ -10060,12 +10028,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			clif_skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0);
 		break;
 
-	case WL_FROSTMISTY:
-		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
-		map_foreachinallrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill_castend_damage_id);
-		break;
-
-	case WL_JACKFROST:
 	case NPC_JACKFROST:
 		clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
 		map_foreachinrange(skill_area_sub,bl,skill_get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
@@ -10111,53 +10073,65 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case WL_SUMMONWB:
 	case WL_SUMMONSTONE:
 		{
-			short element = 0, sctype = 0, pos = -1;
-			struct status_change *sc = status_get_sc(src);
+			status_change *sc = status_get_sc(src);
 
-			if( !sc )
+			if (sc == nullptr)
 				break;
 
-			for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) {
-				if( !sctype && !sc->data[i] )
-					sctype = i; // Take the free SC
-				if( sc->data[i] )
-					pos = max(sc->data[i]->val2,pos);
-			}
+			e_wl_spheres element;
 
-			if( !sctype ) {
-				if( sd ) // No free slots to put SC
-					clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0);
-				break;
+			switch (skill_id) { // Set val2. The SC element for this ball
+				case WL_SUMMONFB:
+					element = WLS_FIRE;
+					break;
+				case WL_SUMMONBL:
+					element = WLS_WIND;
+					break;
+				case WL_SUMMONWB:
+					element = WLS_WATER;
+					break;
+				case WL_SUMMONSTONE:
+					element = WLS_STONE;
+					break;
 			}
 
-			pos++; // Used in val2 for SC. Indicates the order of this ball
-			switch( skill_id ) { // Set val1. The SC element for this ball
-				case WL_SUMMONFB:    element = WLS_FIRE;  break;
-				case WL_SUMMONBL:    element = WLS_WIND;  break;
-				case WL_SUMMONWB:    element = WLS_WATER; break;
-				case WL_SUMMONSTONE: element = WLS_STONE; break;
+			if (skill_lv == 1) {
+				sc_type sphere = SC_NONE;
+
+				for (i = SC_SPHERE_1; i <= SC_SPHERE_5; i++) {
+					if (sc->data[i] == nullptr) {
+						sphere = static_cast<sc_type>(i); // Take the free SC
+						break;
+					}
+				}
+
+				if (sphere == SC_NONE) {
+					if (sd) // No free slots to put SC
+						clif_skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0);
+					break;
+				}
+
+				sc_start2(src, src, sphere, 100, element, skill_lv, skill_get_time(skill_id, skill_lv));
+			} else {
+				for (i = SC_SPHERE_1; i <= SC_SPHERE_5; i++) {
+					status_change_end(src, static_cast<sc_type>(i), INVALID_TIMER); // Removes previous type
+					sc_start2(src, src, static_cast<sc_type>(i), 100, element, skill_lv, skill_get_time(skill_id, skill_lv));
+				}
 			}
 
-			sc_start4(src,src,(enum sc_type)sctype,100,element,pos,skill_lv,0,skill_get_time(skill_id,skill_lv));
-			clif_skill_nodamage(src,bl,skill_id,0,0);
+			clif_skill_nodamage(src, bl, skill_id, 0, 0);
 		}
 		break;
 
-	case WL_READING_SB:
-		if( sd ) {
-			struct status_change *sc = status_get_sc(bl);
-
-			for( i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++)
-				if( sc && !sc->data[i] )
-					break;
-			if( i == SC_MAXSPELLBOOK ) {
-				clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0);
+	case WL_READING_SB_READING:
+		if (sd) {
+			if (pc_checkskill(sd, WL_READING_SB) == 0 || skill_lv < 1 || skill_lv > 10) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPELLBOOK_READING, 0);
 				break;
 			}
 
-			sc_start(src,bl, SC_STOP, 100, skill_lv, INFINITE_TICK); //Can't move while selecting a spellbook.
-			clif_spellbook_list(sd);
 			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
+			skill_spellbook(sd, ITEMID_WL_MB_SG + skill_lv - 1);
 		}
 		break;
 
@@ -11858,6 +11832,7 @@ TIMER_FUNC(skill_castend_id){
 				}
 			case GN_WALLOFTHORN:
 			case SC_ESCAPE:
+			case WL_FROSTMISTY:
 			case SU_CN_POWDERING:
 				ud->skillx = target->x;
 				ud->skilly = target->y;
@@ -12729,6 +12704,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 	case NC_COLDSLOWER:
 	case RK_DRAGONBREATH:
 	case RK_DRAGONBREATH_WATER:
+	case WL_FROSTMISTY:
 	case RL_HAMMER_OF_GOD:
 		// Cast center might be relevant later (e.g. for knockback direction)
 		skill_area_temp[4] = x;
@@ -15237,8 +15213,8 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
 		if (*c >= 2) // Check for two companions for Benedictio. [Skotlex]
 			return 0;
 	}
-	else if (is_chorus || skill_id == WL_COMET) {
-		if (*c == MAX_PARTY) // Check for partners for Chorus or Comet; Cap if the entire party is accounted for.
+	else if (is_chorus) {
+		if (*c == MAX_PARTY) // Check for partners for Chorus; Cap if the entire party is accounted for.
 			return 0;
 	}
 	else if (*c >= 1) // Check for one companion for all other cases.
@@ -15275,11 +15251,6 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
 				if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST )
 					p_sd[(*c)++] = tsd->bl.id;
 				return 1;
-			case WL_COMET:
-			// Comet does not consume Red Gemstones when there is at least 1 Warlock class next to the caster
-				if( ( sd->class_&MAPID_THIRDMASK ) == MAPID_WARLOCK )
-					p_sd[(*c)++] = tsd->bl.id;
-				return 1;
 			default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex]
 				{
 					uint16 skill_lv;
@@ -15367,7 +15338,7 @@ int skill_check_pc_partner(struct map_session_data *sd, uint16 skill_id, uint16
 	memset (p_sd, 0, sizeof(p_sd));
 	i = map_foreachinallrange(skill_check_condition_char_sub, &sd->bl, range, BL_PC, &sd->bl, &c, &p_sd, skill_id);
 
-	if ( skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS && skill_id != WL_COMET && skill_id != WM_GREAT_ECHO ) //Apply the average lv to encore skills.
+	if ( skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS && skill_id != WM_GREAT_ECHO ) //Apply the average lv to encore skills.
 		*skill_lv = (i+(*skill_lv))/(c+1); //I know c should be one, but this shows how it could be used for the average of n partners.
 	return c;
 }
@@ -15980,8 +15951,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 				}
 			}
 			break;
-		case AB_ADORAMUS: // bugreport:7647 mistress card DOES remove requirements for gemstones from Adoramus and Comet -helvetica
-		case WL_COMET:
+		case AB_ADORAMUS: // bugreport:7647 mistress card DOES remove requirements for gemstones from Adoramus -helvetica
 			if( skill_check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && require.itemid[0]
 				&& sd->special_state.no_gemstone == 0
 				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->inventory.u.items_inventory[i].amount < require.amount[0]) ) {
@@ -15993,32 +15963,35 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 		case WL_SUMMONBL:
 		case WL_SUMMONWB:
 		case WL_SUMMONSTONE:
-			if( sc ) {
-				ARR_FIND(SC_SPHERE_1,SC_SPHERE_5+1,i,!sc->data[i]);
-				if( i == SC_SPHERE_5+1 ) { // No more free slots
-					clif_skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0);
+			if (skill_lv == 1 && sc) { // Failure only happens on level 1
+				ARR_FIND(SC_SPHERE_1, SC_SPHERE_5 + 1, i, !sc->data[i]);
+
+				if (i == SC_SPHERE_5 + 1) { // No more free slots
+					clif_skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0);
 					return false;
 				}
 			}
 			break;
 		case WL_TETRAVORTEX: // bugreport:7598 moved sphere check to precast to avoid triggering cooldown per official behavior -helvetica
-			if( sc ) {
-				int j = 0;
+		case WL_RELEASE: {
+				int active_spheres = 0, req_spheres = 0;
 
-				for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
-					if( sc->data[i] ) {
-						j++;
-					}
+				for (i = SC_SPHERE_1; i <= SC_SPHERE_5; i++) {
+					if (sc && sc->data[i])
+						active_spheres++;
+				}
 
-				if( j < 4 ) { // Need 4 spheres minimum
-					clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
+				// Cast requirement
+				if (skill_id == WL_TETRAVORTEX)
+					req_spheres = 4;
+				else if (skill_id == WL_RELEASE && skill_lv == 2) // Only level 2 uses Spheres
+					req_spheres = 1;
+
+				if (active_spheres < req_spheres) { // Need minimum amount of spheres
+					clif_skill_fail(sd, skill_id, (skill_id == WL_RELEASE) ? USESKILL_FAIL_SUMMON_NONE : USESKILL_FAIL_LEVEL, 0);
 					return false;
 				}
 			}
-			else { // no status at all? no spheres present
-				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
-				return false;
-			}
 			break;
 		case GC_HALLUCINATIONWALK:
 			if( sc && (sc->data[SC_HALLUCINATIONWALK] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY]) ) {
@@ -16976,10 +16949,6 @@ struct s_skill_condition skill_get_requirement(struct map_session_data* sd, uint
 							if( itemdb_group_item_exists(IG_GEMSTONE, skill->require.itemid[i]) && (sd->special_state.no_gemstone == 2 || skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 2)) )
 								continue;
 							break;
-						case WL_COMET:
-							if( itemdb_group_item_exists(IG_GEMSTONE, skill->require.itemid[i]) && (sd->special_state.no_gemstone == 2 || skill_check_pc_partner(sd,skill_id,&skill_lv, 1, 0)) )
-								continue;
-							break;
 					}
 
 					req.itemid[i] = skill->require.itemid[i];
@@ -20613,31 +20582,26 @@ int skill_magicdecoy(struct map_session_data *sd, t_itemid nameid) {
 	return 0;
 }
 
-// Warlock Spellbooks. [LimitLine/3CeAM]
+/**
+ * Process Warlock Spellbooks
+ * @param sd: Player data
+ * @param nameid: Spellbook item used
+ */
 void skill_spellbook(struct map_session_data *sd, t_itemid nameid) {
 	nullpo_retv(sd);
 
 	if (reading_spellbook_db.empty())
 		return;
 
-	int i;
 	struct status_change *sc = status_get_sc(&sd->bl);
 
-	status_change_end(&sd->bl, SC_STOP, INVALID_TIMER);
-
-	for (i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) {
-		// No further checks needed
-		if( !sc ){
+	for (int i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) {
+		if (sc == nullptr || sc->data[i] == nullptr)
 			break;
+		if (i == SC_MAXSPELLBOOK) {
+			clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0);
+			return;
 		}
-
-		if( !sc->data[i] )
-			break;
-	}
-
-	if( i > SC_MAXSPELLBOOK ) {
-		clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0);
-		return;
 	}
 
 	std::shared_ptr<s_skill_spellbook_db> spell = reading_spellbook_db.findBook(nameid);
@@ -20647,7 +20611,7 @@ void skill_spellbook(struct map_session_data *sd, t_itemid nameid) {
 
 	uint16 skill_id = spell->skill_id, skill_lv = pc_checkskill(sd, skill_id);
 
-	if (!skill_lv) { // Caster hasn't learned the skill
+	if (skill_lv == 0) { // Caster hasn't learned the skill
 		sc_start(&sd->bl,&sd->bl, SC_SLEEP, 100, 1, skill_get_time(WL_READING_SB, pc_checkskill(sd, WL_READING_SB)));
 		clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_DIFFICULT_SLEEP, 0);
 		return;
@@ -20660,7 +20624,7 @@ void skill_spellbook(struct map_session_data *sd, t_itemid nameid) {
 			clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_PRESERVATION_POINT, 0);
 			return;
 		}
-		for (i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) { // This is how official saves spellbook. [malufett]
+		for (int i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) { // This is how official saves spellbook. [malufett]
 			if (!sc->data[i]) {
 				sc->data[SC_FREEZE_SP]->val2 += points; // increase points
 				sc_start4(&sd->bl,&sd->bl, (sc_type)i, 100, skill_id, skill_lv, points, 0, INFINITE_TICK);

+ 2 - 1
src/map/skill.hpp

@@ -1965,6 +1965,7 @@ enum e_skill {
 	NV_BREAKTHROUGH,
 	NV_HELPANGEL,
 	NV_TRANSCENDENCE,
+	WL_READING_SB_READING,
 
 	HLIF_HEAL = 8001,
 	HLIF_AVOID,
@@ -2261,7 +2262,7 @@ void skill_usave_trigger(struct map_session_data *sd);
 /**
  * Warlock
  **/
-enum wl_spheres {
+enum e_wl_spheres {
 	WLS_FIRE = 0x44,
 	WLS_WIND,
 	WLS_WATER,

+ 14 - 5
src/map/status.cpp

@@ -847,14 +847,11 @@ void initChangeTables(void)
 	/* Warlock */
 	add_sc( WL_WHITEIMPRISON	, SC_WHITEIMPRISON	);
 	set_sc_with_vfx( WL_FROSTMISTY	, SC_FREEZING		, EFST_FROSTMISTY		, SCB_ASPD|SCB_SPEED|SCB_DEF );
-	add_sc( WL_JACKFROST        , SC_FREEZE		  );
 	set_sc( WL_MARSHOFABYSS		, SC_MARSHOFABYSS	, EFST_MARSHOFABYSS	, SCB_AGI|SCB_DEX|SCB_SPEED );
 	set_sc( WL_RECOGNIZEDSPELL	, SC_RECOGNIZEDSPELL	, EFST_RECOGNIZEDSPELL	, SCB_MATK);
 	add_sc( WL_SIENNAEXECRATE   , SC_STONE		  );
 	set_sc( WL_STASIS			, SC_STASIS		, EFST_STASIS		, SCB_NONE );
-	add_sc( WL_CRIMSONROCK      , SC_STUN         );
-	set_sc( WL_HELLINFERNO      , SC_BURNING         , EFST_BURNT           , SCB_MDEF );
-	set_sc( WL_COMET            , SC_BURNING         , EFST_BURNT           , SCB_MDEF );
+	set_sc_with_vfx( WL_COMET   , SC_MAGIC_POISON	, EFST_MAGIC_POISON	, SCB_NONE );
 	set_sc( WL_TELEKINESIS_INTENSE	, SC_TELEKINESIS_INTENSE, EFST_TELEKINESIS_INTENSE, SCB_MATK );
 
 	/* Ranger */
@@ -1385,6 +1382,7 @@ void initChangeTables(void)
 	StatusIconChangeTable[SC_ADD_ATK_DAMAGE] = EFST_ADD_ATK_DAMAGE;
 	StatusIconChangeTable[SC_ADD_MATK_DAMAGE] = EFST_ADD_MATK_DAMAGE;
 	StatusIconChangeTable[SC_ENSEMBLEFATIGUE] = EFST_ENSEMBLEFATIGUE;
+	StatusIconChangeTable[SC_MISTY_FROST] = EFST_MISTY_FROST;
 
 	// Battleground Queue
 	StatusIconChangeTable[SC_ENTRY_QUEUE_APPLY_DELAY] = EFST_ENTRY_QUEUE_APPLY_DELAY;
@@ -1569,6 +1567,7 @@ void initChangeTables(void)
 
 	StatusChangeFlagTable[SC_ANCILLA] |= SCB_REGEN;
 	StatusChangeFlagTable[SC_ENSEMBLEFATIGUE] |= SCB_SPEED|SCB_ASPD;
+	StatusChangeFlagTable[SC_MISTY_FROST] |= SCB_NONE;
 
 #ifdef RENEWAL
 	// renewal EDP increases your weapon atk
@@ -1615,6 +1614,8 @@ void initChangeTables(void)
 	StatusDisplayType[SC_SPRITEMABLE]     = BL_PC;
 	StatusDisplayType[SC_SV_ROOTTWIST]    = BL_PC;
 	StatusDisplayType[SC_HELLS_PLANT]     = BL_PC;
+	StatusDisplayType[SC_MISTY_FROST]     = BL_PC;
+	StatusDisplayType[SC_MAGIC_POISON]    = BL_PC;
 
 	// Costumes
 	StatusDisplayType[SC_MOONSTAR] = BL_PC;
@@ -10325,7 +10326,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_MAGICPOWER:
 			// val1: Skill lv
 			val2 = 1; // Lasts 1 invocation
-			val3 = 5*val1; // Matk% increase
+#ifdef RENEWAL
+			val3 = 10 * val1; // Matk% increase
+#else
+			val3 = 5 * val1; // Matk% increase
+#endif
 			val4 = 0; // 0 = ready to be used, 1 = activated and running
 			break;
 		case SC_SACRIFICE:
@@ -11915,6 +11920,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val2 = 10 + val1 * 5; // Def/Mdef
 			tick = INFINITE_TICK;
 			break;
+		case SC_MAGIC_POISON:
+			val2 = 50; // Attribute Reduction
+			break;
 
 		/* Rebellion */
 		case SC_B_TRAP:
@@ -12248,6 +12256,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 		case SC_CROSSBOWCLAN:
 		case SC_JUMPINGCLAN:
 		case SC_DRESSUP:
+		case SC_MISTY_FROST:
 			val_flag |= 1;
 			break;
 		// Start |1|2 val_flag setting

+ 3 - 5
src/map/status.hpp

@@ -652,11 +652,7 @@ enum sc_type : int16 {
 	SC_SPELLBOOK4,
 	SC_SPELLBOOK5,
 	SC_SPELLBOOK6,
-/**
- * In official server there are only 7 maximum number of spell books that can be memorized
- * To increase the maximum value just add another status type before SC_MAXSPELLBOOK (ex. SC_SPELLBOOK7, SC_SPELLBOOK8 and so on)
- **/
-	SC_MAXSPELLBOOK,
+	SC_MAXSPELLBOOK, // SC_SPELLBOOK7
 	/* Max HP & SP */
 	SC_INCMHP,
 	SC_INCMSP,
@@ -933,6 +929,8 @@ enum sc_type : int16 {
 	SC_LUXANIMA,
 	SC_REUSE_LIMIT_LUXANIMA,
 	SC_ENSEMBLEFATIGUE,
+	SC_MISTY_FROST,
+	SC_MAGIC_POISON,
 
 #ifdef RENEWAL
 	SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled