diff --git a/db/job_db2.txt b/db/job_db2.txt index 526e87663c..c02bb99015 100644 --- a/db/job_db2.txt +++ b/db/job_db2.txt @@ -312,18 +312,15 @@ // Baby Star Gladiator (Union) 4238,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 //================================ -// Note: Star Emperor and Soul Reaper bonus stats are unknown. Using Star Gladiator and Soul Linker's -// bonus stats for now until I know the official ones. -// // Star Emperor -4239,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 +4239,1,5,0,0,2,0,4,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,1,3,4,0,5,0,2,5,1,0,0,5,2,6,3,5,1,0,2,3,1,0,5,0,2,1,0,5,0,0,0,0,0,1,0,0,2,0 // Soul Reaper -4240,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5 +4240,4,5,0,0,4,3,5,0,0,0,5,4,2,0,5,4,3,0,1,5,2,0,0,3,4,5,0,1,2,5,4,0,0,5,2,0,3,5,4,0,2,3,1,4,5,0,2,0,4,5,0,2,0,4,0,0,0,0,4,0 // Baby Star Emperor -4241,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 +4241,1,5,0,0,2,0,4,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,1,3,4,0,5,0,2,5,1,0,0,5,2,6,3,5,1,0,2,3,1,0,5,0,2,1,0,5,0,0,0,0,0,1,0,0,2,0 // Baby Soul Reaper -4242,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5 +4242,4,5,0,0,4,3,5,0,0,0,5,4,2,0,5,4,3,0,1,5,2,0,0,3,4,5,0,1,2,5,4,0,0,5,2,0,3,5,4,0,2,3,1,4,5,0,2,0,4,5,0,2,0,4,0,0,0,0,4,0 // Star Emperor (Union) -4243,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 +4243,1,5,0,0,2,0,4,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,1,3,4,0,5,0,2,5,1,0,0,5,2,6,3,5,1,0,2,3,1,0,5,0,2,1,0,5,0,0,0,0,0,1,0,0,2,0 // Baby Star Emperor (Union) -4244,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 +4244,1,5,0,0,2,0,4,1,6,0,5,1,2,0,4,6,3,0,1,5,2,0,1,3,4,0,5,0,2,5,1,0,0,5,2,6,3,5,1,0,2,3,1,0,5,0,2,1,0,5,0,0,0,0,0,1,0,0,2,0 diff --git a/db/pre-re/skill_db.yml b/db/pre-re/skill_db.yml index 9a5b7bc79d..fd49f775ab 100644 --- a/db/pre-re/skill_db.yml +++ b/db/pre-re/skill_db.yml @@ -28317,6 +28317,163 @@ Body: Element: Weapon Requires: SpCost: 1 + - Id: 2574 + Name: SJ_LIGHTOFMOON + Description: Light of Moon + MaxLevel: 1 + - Id: 2575 + Name: SJ_LUNARSTANCE + Description: Lunar Stance + MaxLevel: 1 + - Id: 2576 + Name: SJ_FULLMOONKICK + Description: Full Moon Kick + MaxLevel: 1 + - Id: 2577 + Name: SJ_LIGHTOFSTAR + Description: Light of Star + MaxLevel: 1 + - Id: 2578 + Name: SJ_STARSTANCE + Description: Star Stance + MaxLevel: 1 + - Id: 2579 + Name: SJ_NEWMOONKICK + Description: New Moon Kick + MaxLevel: 1 + - Id: 2580 + Name: SJ_FLASHKICK + Description: Flash Kick + MaxLevel: 1 + - Id: 2581 + Name: SJ_STAREMPEROR + Description: Star Emperor + MaxLevel: 1 + - Id: 2582 + Name: SJ_NOVAEXPLOSING + Description: Nova Explosion + MaxLevel: 1 + Type: Misc + - Id: 2583 + Name: SJ_UNIVERSESTANCE + Description: Universe Stance + MaxLevel: 1 + - Id: 2584 + Name: SJ_FALLINGSTAR + Description: Falling Star + MaxLevel: 1 + - Id: 2585 + Name: SJ_GRAVITYCONTROL + Description: Gravity Control + MaxLevel: 1 + - Id: 2586 + Name: SJ_BOOKOFDIMENSION + Description: Book of Dimension + MaxLevel: 1 + - Id: 2587 + Name: SJ_BOOKOFCREATINGSTAR + Description: Book of Creating Star + MaxLevel: 1 + - Id: 2588 + Name: SJ_DOCUMENT + Description: Document of Sun Moon and Star + MaxLevel: 1 + - Id: 2589 + Name: SJ_PURIFY + Description: Purification of Sun Moon and Star + MaxLevel: 1 + - Id: 2590 + Name: SJ_LIGHTOFSUN + Description: Light of Sun + MaxLevel: 1 + - Id: 2591 + Name: SJ_SUNSTANCE + Description: Sun Stance + MaxLevel: 1 + - Id: 2592 + Name: SJ_SOLARBURST + Description: Solar Burst + MaxLevel: 1 + - Id: 2593 + Name: SJ_PROMINENCEKICK + Description: Prominence Kick + MaxLevel: 1 + - Id: 2594 + Name: SJ_FALLINGSTAR_ATK + Description: Falling Star Attack + MaxLevel: 1 + - Id: 2595 + Name: SJ_FALLINGSTAR_ATK2 + Description: Falling Star Attack 2 + MaxLevel: 1 + - Id: 2596 + Name: SP_SOULGOLEM + Description: Golem's Soul + MaxLevel: 1 + - Id: 2597 + Name: SP_SOULSHADOW + Description: Shadow's Soul + MaxLevel: 1 + - Id: 2598 + Name: SP_SOULFALCON + Description: Falcon's Soul + MaxLevel: 1 + - Id: 2599 + Name: SP_SOULFAIRY + Description: Fairy's Soul + MaxLevel: 1 + - Id: 2600 + Name: SP_CURSEEXPLOSION + Description: Curse Explosion + MaxLevel: 1 + - Id: 2601 + Name: SP_SOULCURSE + Description: Soul Curse + MaxLevel: 1 + - Id: 2602 + Name: SP_SPA + Description: Espa + MaxLevel: 1 + - Id: 2603 + Name: SP_SHA + Description: Esha + MaxLevel: 1 + - Id: 2604 + Name: SP_SWHOO + Description: Eswhoo + MaxLevel: 1 + - Id: 2605 + Name: SP_SOULUNITY + Description: Soul Unity + MaxLevel: 1 + - Id: 2606 + Name: SP_SOULDIVISION + Description: Soul Division + MaxLevel: 1 + - Id: 2607 + Name: SP_SOULREAPER + Description: Soul Reaper + MaxLevel: 1 + - Id: 2608 + Name: SP_SOULREVOLVE + Description: Soul Revolution + MaxLevel: 1 + - Id: 2609 + Name: SP_SOULCOLLECT + Description: Soul Collect + MaxLevel: 1 + - Id: 2610 + Name: SP_SOULEXPLOSION + Description: Soul Explosion + MaxLevel: 1 + - Id: 2611 + Name: SP_SOULENERGY + Description: Soul Energy Research + MaxLevel: 1 + - Id: 2612 + Name: SP_KAUTE + Description: Kaute + MaxLevel: 1 - Id: 3001 Name: KO_YAMIKUMO Description: Shadow Hiding diff --git a/db/re/skill_db.yml b/db/re/skill_db.yml index 9a217836cb..0d523b5d82 100644 --- a/db/re/skill_db.yml +++ b/db/re/skill_db.yml @@ -29444,7 +29444,22 @@ Body: Description: Light of Moon MaxLevel: 5 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Duration1: + - Level: 1 + Time: 20000 + - Level: 2 + Time: 30000 + - Level: 3 + Time: 40000 + - Level: 4 + Time: 50000 + - Level: 5 + Time: 60000 Requires: SpCost: 40 - Id: 2575 @@ -29452,15 +29467,28 @@ Body: Description: Lunar Stance MaxLevel: 3 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true Requires: SpCost: 10 - Id: 2576 Name: SJ_FULLMOONKICK Description: Full Moon Kick - MaxLevel: 7 + MaxLevel: 10 + Type: Weapon TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 3 CastCancel: true + Duration1: 20000 + Cooldown: 1000 Requires: SpCost: - Level: 1 @@ -29482,7 +29510,22 @@ Body: Description: Light of Star MaxLevel: 5 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Duration1: + - Level: 1 + Time: 20000 + - Level: 2 + Time: 30000 + - Level: 3 + Time: 40000 + - Level: 4 + Time: 50000 + - Level: 5 + Time: 60000 Requires: SpCost: 40 - Id: 2578 @@ -29490,6 +29533,10 @@ Body: Description: Star Stance MaxLevel: 3 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true Requires: SpCost: 10 @@ -29497,8 +29544,18 @@ Body: Name: SJ_NEWMOONKICK Description: New Moon Kick MaxLevel: 7 + Type: Weapon TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 3 CastCancel: true + CastTime: 1000 + Duration1: 15000 + Cooldown: 1000 Requires: SpCost: - Level: 1 @@ -29519,9 +29576,28 @@ Body: Name: SJ_FLASHKICK Description: Flash Kick MaxLevel: 7 + Type: Weapon TargetType: Attack Range: 1 + Hit: Single + HitCount: 1 + Element: Weapon CastCancel: true + Duration1: + - Level: 1 + Time: 4000 + - Level: 2 + Time: 5000 + - Level: 3 + Time: 6000 + - Level: 4 + Time: 7000 + - Level: 5 + Time: 8000 + - Level: 6 + Time: 9000 + - Level: 7 + Time: 10000 Requires: SpCost: - Level: 1 @@ -29540,10 +29616,21 @@ Body: Amount: 15 - Id: 2581 Name: SJ_STAREMPEROR - Description: Star Emperor + Description: Star Emperor Advent MaxLevel: 5 + Type: Weapon TargetType: Self + DamageFlags: + Splash: true + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 3 CastCancel: true + AfterCastActDelay: 1000 + Duration1: 7000 + Cooldown: 10000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29558,11 +29645,23 @@ Body: Amount: 90 - Id: 2582 Name: SJ_NOVAEXPLOSING - Description: Nova Explosing + Description: Nova Explosion MaxLevel: 5 + Type: Misc TargetType: Attack + DamageFlags: + IgnoreElement: true + IgnoreFlee: true + IgnoreDefCard: true Range: 3 + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 5000 + AfterCastActDelay: 1000 + Duration1: 2000 + Cooldown: 20000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29580,15 +29679,41 @@ Body: Description: Universe Stance MaxLevel: 3 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true Requires: SpCost: 10 - Id: 2584 Name: SJ_FALLINGSTAR Description: Falling Star - MaxLevel: 7 + MaxLevel: 10 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 1000 + Duration1: 126000 + Cooldown: + - Level: 1 + Time: 120000 + - Level: 2 + Time: 140000 + - Level: 3 + Time: 160000 + - Level: 4 + Time: 180000 + - Level: 5 + Time: 200000 + - Level: 6 + Time: 220000 + - Level: 7 + Time: 240000 + FixedCastTime: 2000 Requires: SpCost: - Level: 1 @@ -29610,8 +29735,16 @@ Body: Description: Gravity Control MaxLevel: 1 TargetType: Attack + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: 5000 + Cooldown: 20000 Requires: SpCost: 80 - Id: 2586 @@ -29619,16 +29752,52 @@ Body: Description: Book of Dimension MaxLevel: 5 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Duration1: 60000 + Duration2: 30000 + Cooldown: + - Level: 1 + Time: 150000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 60000 + - Level: 5 + Time: 30000 Requires: SpCost: 40 - Id: 2587 Name: SJ_BOOKOFCREATINGSTAR Description: Book of Creating Star MaxLevel: 5 + Type: Weapon TargetType: Ground Range: 7 + Hit: Single + HitCount: 1 + Element: Weapon CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 6000 + - Level: 2 + Time: 7000 + - Level: 3 + Time: 8000 + - Level: 4 + Time: 9000 + - Level: 5 + Time: 10000 + Cooldown: 15000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29641,24 +29810,53 @@ Body: Amount: 65 - Level: 5 Amount: 70 + Unit: + Id: Creatingstar + Layout: 2 + Interval: -1 + Target: Enemy + Flag: + NoOverlap: true + PathCheck: true + NoKnockback: true - Id: 2588 Name: SJ_DOCUMENT - Description: Document + Description: Document of Sun Moon and Star MaxLevel: 3 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Cooldown: 60000 Requires: SpCost: 60 - Id: 2589 Name: SJ_PURIFY - Description: Purify + Description: Purification of Sun Moon and Star MaxLevel: 1 - Id: 2590 Name: SJ_LIGHTOFSUN Description: Light of Sun MaxLevel: 5 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Duration1: + - Level: 1 + Time: 20000 + - Level: 2 + Time: 30000 + - Level: 3 + Time: 40000 + - Level: 4 + Time: 50000 + - Level: 5 + Time: 60000 Requires: SpCost: 40 - Id: 2591 @@ -29666,15 +29864,27 @@ Body: Description: Sun Stance MaxLevel: 3 TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true Requires: SpCost: 10 - Id: 2592 Name: SJ_SOLARBURST Description: Solar Burst - MaxLevel: 7 + MaxLevel: 10 + Type: Weapon TargetType: Self + DamageFlags: + Splash: true + Hit: Multi_Hit + HitCount: -3 + Element: Weapon + SplashArea: 3 CastCancel: true + AfterCastActDelay: 500 Requires: SpCost: - Level: 1 @@ -29695,18 +29905,35 @@ Body: Name: SJ_PROMINENCEKICK Description: Prominence Kick MaxLevel: 7 + Type: Weapon TargetType: Attack + DamageFlags: + Splash: true Range: 1 + Hit: Single + HitCount: 1 + Element: Weapon + SplashArea: 1 CastCancel: true + AfterCastActDelay: 1000 + CastDelayFlags: + IgnoreStatus: true Requires: SpCost: 20 - Id: 2594 Name: SJ_FALLINGSTAR_ATK Description: Falling Star Attack MaxLevel: 7 - TargetType: Attack + Type: Weapon + TargetType: Self + DamageFlags: + Splash: true Flags: IsChorus: true + Hit: Multi_Hit + HitCount: -3 + Element: Weapon + SplashArea: 2 CastCancel: true Requires: SpCost: 1 @@ -29714,19 +29941,44 @@ Body: Name: SJ_FALLINGSTAR_ATK2 Description: Falling Star Attack 2 MaxLevel: 7 + Type: Weapon TargetType: Attack + DamageFlags: + Splash: true Flags: IsChorus: true + Range: 1 + Hit: Multi_Hit + HitCount: -3 + Element: Weapon + SplashArea: 2 CastCancel: true Requires: SpCost: 1 - Id: 2596 Name: SP_SOULGOLEM - Description: Soul Golem + Description: Golem's Soul MaxLevel: 5 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 Requires: SpCost: - Level: 1 @@ -29739,13 +29991,31 @@ Body: Amount: 100 - Level: 5 Amount: 50 + SpiritSphereCost: 1 - Id: 2597 Name: SP_SOULSHADOW - Description: Soul Shadow + Description: Shadow's Soul MaxLevel: 5 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 Requires: SpCost: - Level: 1 @@ -29758,13 +30028,31 @@ Body: Amount: 100 - Level: 5 Amount: 50 + SpiritSphereCost: 1 - Id: 2598 Name: SP_SOULFALCON - Description: Soul Falcon + Description: Falcon's Soul MaxLevel: 5 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 Requires: SpCost: - Level: 1 @@ -29777,13 +30065,31 @@ Body: Amount: 100 - Level: 5 Amount: 50 + SpiritSphereCost: 1 - Id: 2599 Name: SP_SOULFAIRY - Description: Soul Fairy + Description: Fairy's Soul MaxLevel: 5 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 180000 + - Level: 4 + Time: 240000 + - Level: 5 + Time: 300000 Requires: SpCost: - Level: 1 @@ -29796,13 +30102,25 @@ Body: Amount: 100 - Level: 5 Amount: 50 + SpiritSphereCost: 1 - Id: 2600 Name: SP_CURSEEXPLOSION Description: Curse Explosion - MaxLevel: 5 + MaxLevel: 10 + Type: Magic TargetType: Attack + DamageFlags: + Splash: true Range: 9 + Hit: Multi_Hit + HitCount: -7 + Element: Dark + SplashArea: 3 CastCancel: true + CastTime: 3000 + AfterCastActDelay: 500 + Cooldown: 1000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29819,18 +30137,38 @@ Body: Name: SP_SOULCURSE Description: Soul Curse MaxLevel: 5 + Type: Magic TargetType: Attack + DamageFlags: + NoDamage: true + Splash: true Range: 9 + Hit: Single + HitCount: 1 + SplashArea: 3 CastCancel: true + CastTime: 1000 + AfterCastActDelay: 500 + Duration1: 20000 + Cooldown: 5000 + FixedCastTime: 1000 Requires: SpCost: 70 + SpiritSphereCost: 3 - Id: 2602 Name: SP_SPA Description: Espa - MaxLevel: 5 + MaxLevel: 10 + Type: Magic TargetType: Attack Range: 9 + Hit: Single + HitCount: 1 + Element: Endowed CastCancel: true + CastTime: 500 + Duration1: 5000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29843,13 +30181,65 @@ Body: Amount: 64 - Level: 5 Amount: 68 + SpiritSphereCost: + - Level: 1 + Amount: 1 + - Level: 2 + Amount: 1 + - Level: 3 + Amount: 1 + - Level: 4 + Amount: 1 + - Level: 5 + Amount: 1 + - Level: 6 + Amount: 1 + - Level: 7 + Amount: 1 + - Level: 8 + Amount: 1 + - Level: 9 + Amount: 1 - Id: 2603 Name: SP_SHA Description: Esha MaxLevel: 5 + Type: Magic TargetType: Attack + DamageFlags: + Splash: true Range: 9 + Hit: Single + HitCount: 1 + Element: Endowed + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 2 CastCancel: true + CastTime: 500 + AfterCastActDelay: 500 + Duration1: + - Level: 1 + Time: 3000 + - Level: 2 + Time: 4000 + - Level: 3 + Time: 5000 + - Level: 4 + Time: 6000 + - Level: 5 + Time: 7000 + Duration2: 5000 + Cooldown: 3000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29862,13 +30252,40 @@ Body: Amount: 24 - Level: 5 Amount: 26 + SpiritSphereCost: 1 - Id: 2604 Name: SP_SWHOO Description: Eswhoo - MaxLevel: 7 + MaxLevel: 10 + Type: Magic TargetType: Attack + DamageFlags: + Splash: true Range: 9 + Hit: Multi_Hit + HitCount: -5 + Element: Endowed + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 1 + - Level: 4 + Area: 2 + - Level: 5 + Area: 2 + - Level: 6 + Area: 2 + - Level: 7 + Area: 3 CastCancel: true + CastTime: 500 + AfterCastActDelay: 500 + Duration1: 5000 + Cooldown: 2000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29885,13 +30302,85 @@ Body: Amount: 86 - Level: 7 Amount: 90 + SpiritSphereCost: + - Level: 1 + Amount: 2 + - Level: 2 + Amount: 2 + - Level: 3 + Amount: 2 + - Level: 4 + Amount: 2 + - Level: 5 + Amount: 2 + - Level: 6 + Amount: 2 + - Level: 7 + Amount: 2 + - Level: 8 + Amount: 2 + - Level: 9 + Amount: 2 + - Level: 10 + Amount: 1 - Id: 2605 Name: SP_SOULUNITY Description: Soul Unity MaxLevel: 7 + Type: Magic TargetType: Self + DamageFlags: + NoDamage: true + Splash: true Range: 11 + Hit: Single + HitCount: 1 + SplashArea: + - Level: 1 + Area: 1 + - Level: 2 + Area: 1 + - Level: 3 + Area: 2 + - Level: 4 + Area: 2 + - Level: 5 + Area: 3 + - Level: 6 + Area: 3 + - Level: 7 + Area: 4 CastCancel: true + AfterCastActDelay: 1000 + Duration1: + - Level: 1 + Time: 30000 + - Level: 2 + Time: 60000 + - Level: 3 + Time: 90000 + - Level: 4 + Time: 120000 + - Level: 5 + Time: 150000 + - Level: 6 + Time: 180000 + - Level: 7 + Time: 210000 + Cooldown: + - Level: 2 + Time: 30000 + - Level: 3 + Time: 60000 + - Level: 4 + Time: 90000 + - Level: 5 + Time: 120000 + - Level: 6 + Time: 150000 + - Level: 7 + Time: 180000 + FixedCastTime: 4000 Requires: SpCost: - Level: 1 @@ -29908,13 +30397,24 @@ Body: Amount: 54 - Level: 7 Amount: 56 + SpiritSphereCost: 10 - Id: 2606 Name: SP_SOULDIVISION Description: Soul Division MaxLevel: 5 + Type: Magic TargetType: Attack + DamageFlags: + NoDamage: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 500 + AfterCastActDelay: 500 + Duration1: 5000 + Cooldown: 3000 + FixedCastTime: 1500 Requires: SpCost: - Level: 1 @@ -29927,12 +30427,42 @@ Body: Amount: 48 - Level: 5 Amount: 52 + SpiritSphereCost: 1 - Id: 2607 Name: SP_SOULREAPER Description: Soul Reaper MaxLevel: 5 + Type: Magic TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 3000 + Duration1: + - Level: 1 + Time: 90000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 150000 + - Level: 4 + Time: 180000 + - Level: 5 + Time: 210000 + Cooldown: + - Level: 1 + Time: 90000 + - Level: 2 + Time: 120000 + - Level: 3 + Time: 150000 + - Level: 4 + Time: 180000 + - Level: 5 + Time: 210000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29945,13 +30475,24 @@ Body: Amount: 48 - Level: 5 Amount: 50 + SpiritSphereCost: 2 - Id: 2608 Name: SP_SOULREVOLVE - Description: Soul Revolve + Description: Soul Revolution MaxLevel: 3 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true + Flags: + PartyOnly: true Range: 9 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 500 + Cooldown: 3000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29964,17 +30505,45 @@ Body: Name: SP_SOULCOLLECT Description: Soul Collect MaxLevel: 5 + Type: Magic TargetType: Self + DamageFlags: + NoDamage: true + Hit: Single + HitCount: 1 CastCancel: true + Duration1: + - Level: 1 + Time: 60000 + - Level: 2 + Time: 50000 + - Level: 3 + Time: 40000 + - Level: 4 + Time: 30000 + - Level: 5 + Time: 20000 + Duration2: 600000 Requires: SpCost: 100 - Id: 2610 Name: SP_SOULEXPLOSION Description: Soul Explosion MaxLevel: 5 + Type: Misc TargetType: Attack + DamageFlags: + IgnoreElement: true + IgnoreFlee: true + IgnoreDefCard: true Range: 7 + Hit: Single + HitCount: 1 CastCancel: true + CastTime: 2000 + AfterCastActDelay: 500 + Cooldown: 60000 + FixedCastTime: 1000 Requires: SpCost: - Level: 1 @@ -29987,17 +30556,25 @@ Body: Amount: 120 - Level: 5 Amount: 150 + SpiritSphereCost: 10 - Id: 2611 Name: SP_SOULENERGY - Description: Soul Energy + Description: Soul Energy Research MaxLevel: 5 - Id: 2612 Name: SP_KAUTE Description: Kaute MaxLevel: 5 + Type: Magic TargetType: Support + DamageFlags: + NoDamage: true Range: 7 + Hit: Single + HitCount: 1 CastCancel: true + AfterCastActDelay: 1000 + Cooldown: 5000 Requires: SpCost: - Level: 1 @@ -30010,6 +30587,7 @@ Body: Amount: 42 - Level: 5 Amount: 48 + SpiritSphereCost: 5 - Id: 3001 Name: KO_YAMIKUMO Description: Shadow Hiding diff --git a/db/re/skill_nocast_db.txt b/db/re/skill_nocast_db.txt index 43a1de57e1..2342350964 100644 --- a/db/re/skill_nocast_db.txt +++ b/db/re/skill_nocast_db.txt @@ -62,6 +62,7 @@ 2284,4 //SC_FATALMENACE 2300,4 //SC_DIMENSIONDOOR 5063,4 //WE_CALLALLFAMILY +462,4 //SL_KAIZEL //---------------------------------------------------------------------------- // Battlegrounds @@ -100,6 +101,8 @@ 2284,8 //SC_FATALMENACE 2300,8 //SC_DIMENSIONDOOR 5063,8 //WE_CALLALLFAMILY +5023,8 //SU_LOPE +462,8 //SL_KAIZEL //---------------------------------------------------------------------------- // Mixed @@ -184,6 +187,8 @@ //---------------------------------------------------------------------------- 426,256 //TK_HIGHJUMP 290,256 //SA_ABRACADABRA +5023,256 //SU_LOPE +462,256 //SL_KAIZEL //---------------------------------------------------------------------------- // Zone 5 - Sealed Shrine diff --git a/db/re/skill_tree.txt b/db/re/skill_tree.txt index 775d3aafb7..e63ea3e225 100644 --- a/db/re/skill_tree.txt +++ b/db/re/skill_tree.txt @@ -6203,7 +6203,7 @@ 4239,444,1,443,9,0,0,0,0,0,0,0,0 //SG_FUSION#Union of the Sun, Moon and Stars# 4239,2574,5,2576,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFMOON## 4239,2575,3,2588,1,0,0,0,0,0,0,0,0 //SJ_LUNARSTANCE## -4239,2576,7,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## +4239,2576,10,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## 4239,2577,5,2584,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSTAR## 4239,2578,3,2588,1,0,0,0,0,0,0,0,0 //SJ_STARSTANCE## 4239,2579,7,2575,1,0,0,0,0,0,0,0,0 //SJ_NEWMOONKICK## @@ -6211,7 +6211,7 @@ 4239,2581,5,2582,5,2583,3,0,0,0,0,0,0 //SJ_STAREMPEROR## 4239,2582,5,2583,1,0,0,0,0,0,0,0,0 //SJ_NOVAEXPLOSING## 4239,2583,3,2575,3,2578,3,2591,3,0,0,0,0 //SJ_UNIVERSESTANCE## -4239,2584,7,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## +4239,2584,10,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## 4239,2585,1,2583,1,0,0,0,0,0,0,0,0 //SJ_GRAVITYCONTROL## 4239,2586,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFDIMENSION## 4239,2587,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFCREATINGSTAR## @@ -6219,7 +6219,7 @@ 4239,2589,1,441,10,0,0,0,0,0,0,0,0 //SJ_PURIFY## 4239,2590,5,2592,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSUN## 4239,2591,3,2588,1,0,0,0,0,0,0,0,0 //SJ_SUNSTANCE## -4239,2592,7,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## +4239,2592,10,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## 4239,2593,7,2591,1,0,0,0,0,0,0,0,0 //SJ_PROMINENCEKICK## 4239,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# @@ -6274,13 +6274,13 @@ 4240,2597,5,2605,5,0,0,0,0,0,0,0,0 //SP_SOULSHADOW## 4240,2598,5,2608,2,0,0,0,0,0,0,0,0 //SP_SOULFALCON## 4240,2599,5,2605,5,0,0,0,0,0,0,0,0 //SP_SOULFAIRY## -4240,2600,5,2601,3,0,0,0,0,0,0,0,0 //SP_CURSEEXPLOSION## +4240,2600,10,2601,3,0,0,0,0,0,0,0,0 //SP_CURSEEXPLOSION## 4240,2601,5,2607,3,0,0,0,0,0,0,0,0 //SP_SOULCURSE## -4240,2602,5,2603,1,0,0,0,0,0,0,0,0 //SP_SPA## +4240,2602,10,2603,1,0,0,0,0,0,0,0,0 //SP_SPA## 4240,2603,5,2607,3,0,0,0,0,0,0,0,0 //SP_SHA## -4240,2604,7,2602,3,0,0,0,0,0,0,0,0 //SP_SWHOO## +4240,2604,10,2602,3,0,0,0,0,0,0,0,0 //SP_SWHOO## 4240,2605,7,2611,3,0,0,0,0,0,0,0,0 //SP_SOULUNITY## -4240,2606,5,2602,5,2603,5,0,0,0,0,0,0 //SP_SOULDIVISION## +4240,2606,5,2602,10,2603,5,0,0,0,0,0,0 //SP_SOULDIVISION## 4240,2607,5,2609,1,0,0,0,0,0,0,0,0 //SP_SOULREAPER## 4240,2608,3,2611,3,2612,3,0,0,0,0,0,0 //SP_SOULREVOLVE## 4240,2609,5,0,0,0,0,0,0,0,0,0,0 //SP_SOULCOLLECT## @@ -6329,7 +6329,7 @@ 4241,444,1,443,9,0,0,0,0,0,0,0,0 //SG_FUSION#Union of the Sun, Moon and Stars# 4241,2574,5,2576,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFMOON## 4241,2575,3,2588,1,0,0,0,0,0,0,0,0 //SJ_LUNARSTANCE## -4241,2576,7,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## +4241,2576,10,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## 4241,2577,5,2584,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSTAR## 4241,2578,3,2588,1,0,0,0,0,0,0,0,0 //SJ_STARSTANCE## 4241,2579,7,2575,1,0,0,0,0,0,0,0,0 //SJ_NEWMOONKICK## @@ -6337,7 +6337,7 @@ 4241,2581,5,2582,5,2583,3,0,0,0,0,0,0 //SJ_STAREMPEROR## 4241,2582,5,2583,1,0,0,0,0,0,0,0,0 //SJ_NOVAEXPLOSING## 4241,2583,3,2575,3,2578,3,2591,3,0,0,0,0 //SJ_UNIVERSESTANCE## -4241,2584,7,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## +4241,2584,10,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## 4241,2585,1,2583,1,0,0,0,0,0,0,0,0 //SJ_GRAVITYCONTROL## 4241,2586,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFDIMENSION## 4241,2587,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFCREATINGSTAR## @@ -6345,7 +6345,7 @@ 4241,2589,1,441,10,0,0,0,0,0,0,0,0 //SJ_PURIFY## 4241,2590,5,2592,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSUN## 4241,2591,3,2588,1,0,0,0,0,0,0,0,0 //SJ_SUNSTANCE## -4241,2592,7,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## +4241,2592,10,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## 4241,2593,7,2591,1,0,0,0,0,0,0,0,0 //SJ_PROMINENCEKICK## 4241,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby# 4241,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent# @@ -6402,13 +6402,13 @@ 4242,2597,5,2605,5,0,0,0,0,0,0,0,0 //SP_SOULSHADOW## 4242,2598,5,2608,2,0,0,0,0,0,0,0,0 //SP_SOULFALCON## 4242,2599,5,2605,5,0,0,0,0,0,0,0,0 //SP_SOULFAIRY## -4242,2600,5,2601,3,0,0,0,0,0,0,0,0 //SP_CURSEEXPLOSION## +4242,2600,10,2601,3,0,0,0,0,0,0,0,0 //SP_CURSEEXPLOSION## 4242,2601,5,2607,3,0,0,0,0,0,0,0,0 //SP_SOULCURSE## -4242,2602,5,2603,1,0,0,0,0,0,0,0,0 //SP_SPA## +4242,2602,10,2603,1,0,0,0,0,0,0,0,0 //SP_SPA## 4242,2603,5,2607,3,0,0,0,0,0,0,0,0 //SP_SHA## -4242,2604,7,2602,3,0,0,0,0,0,0,0,0 //SP_SWHOO## +4242,2604,10,2602,3,0,0,0,0,0,0,0,0 //SP_SWHOO## 4242,2605,7,2611,3,0,0,0,0,0,0,0,0 //SP_SOULUNITY## -4242,2606,5,2602,5,2603,5,0,0,0,0,0,0 //SP_SOULDIVISION## +4242,2606,5,2602,10,2603,5,0,0,0,0,0,0 //SP_SOULDIVISION## 4242,2607,5,2609,1,0,0,0,0,0,0,0,0 //SP_SOULREAPER## 4242,2608,3,2611,3,2612,3,0,0,0,0,0,0 //SP_SOULREVOLVE## 4242,2609,5,0,0,0,0,0,0,0,0,0,0 //SP_SOULCOLLECT## @@ -6459,7 +6459,7 @@ 4243,444,1,443,9,0,0,0,0,0,0,0,0 //SG_FUSION#Union of the Sun, Moon and Stars# 4243,2574,5,2576,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFMOON## 4243,2575,3,2588,1,0,0,0,0,0,0,0,0 //SJ_LUNARSTANCE## -4243,2576,7,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## +4243,2576,10,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## 4243,2577,5,2584,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSTAR## 4243,2578,3,2588,1,0,0,0,0,0,0,0,0 //SJ_STARSTANCE## 4243,2579,7,2575,1,0,0,0,0,0,0,0,0 //SJ_NEWMOONKICK## @@ -6467,7 +6467,7 @@ 4243,2581,5,2582,5,2583,3,0,0,0,0,0,0 //SJ_STAREMPEROR## 4243,2582,5,2583,1,0,0,0,0,0,0,0,0 //SJ_NOVAEXPLOSING## 4243,2583,3,2575,3,2578,3,2591,3,0,0,0,0 //SJ_UNIVERSESTANCE## -4243,2584,7,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## +4243,2584,10,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## 4243,2585,1,2583,1,0,0,0,0,0,0,0,0 //SJ_GRAVITYCONTROL## 4243,2586,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFDIMENSION## 4243,2587,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFCREATINGSTAR## @@ -6475,7 +6475,7 @@ 4243,2589,1,441,10,0,0,0,0,0,0,0,0 //SJ_PURIFY## 4243,2590,5,2592,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSUN## 4243,2591,3,2588,1,0,0,0,0,0,0,0,0 //SJ_SUNSTANCE## -4243,2592,7,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## +4243,2592,10,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## 4243,2593,7,2591,1,0,0,0,0,0,0,0,0 //SJ_PROMINENCEKICK## 4243,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# @@ -6519,7 +6519,7 @@ 4244,444,1,443,9,0,0,0,0,0,0,0,0 //SG_FUSION#Union of the Sun, Moon and Stars# 4244,2574,5,2576,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFMOON## 4244,2575,3,2588,1,0,0,0,0,0,0,0,0 //SJ_LUNARSTANCE## -4244,2576,7,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## +4244,2576,10,2579,7,0,0,0,0,0,0,0,0 //SJ_FULLMOONKICK## 4244,2577,5,2584,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSTAR## 4244,2578,3,2588,1,0,0,0,0,0,0,0,0 //SJ_STARSTANCE## 4244,2579,7,2575,1,0,0,0,0,0,0,0,0 //SJ_NEWMOONKICK## @@ -6527,7 +6527,7 @@ 4244,2581,5,2582,5,2583,3,0,0,0,0,0,0 //SJ_STAREMPEROR## 4244,2582,5,2583,1,0,0,0,0,0,0,0,0 //SJ_NOVAEXPLOSING## 4244,2583,3,2575,3,2578,3,2591,3,0,0,0,0 //SJ_UNIVERSESTANCE## -4244,2584,7,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## +4244,2584,10,2580,7,0,0,0,0,0,0,0,0 //SJ_FALLINGSTAR## 4244,2585,1,2583,1,0,0,0,0,0,0,0,0 //SJ_GRAVITYCONTROL## 4244,2586,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFDIMENSION## 4244,2587,5,2581,3,2588,3,0,0,0,0,0,0 //SJ_BOOKOFCREATINGSTAR## @@ -6535,7 +6535,7 @@ 4244,2589,1,441,10,0,0,0,0,0,0,0,0 //SJ_PURIFY## 4244,2590,5,2592,3,0,0,0,0,0,0,0,0 //SJ_LIGHTOFSUN## 4244,2591,3,2588,1,0,0,0,0,0,0,0,0 //SJ_SUNSTANCE## -4244,2592,7,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## +4244,2592,10,2593,7,0,0,0,0,0,0,0,0 //SJ_SOLARBURST## 4244,2593,7,2591,1,0,0,0,0,0,0,0,0 //SJ_PROMINENCEKICK## 4244,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby# 4244,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent# diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index d899b00d5b..d75e9fa42c 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -1309,7 +1309,7 @@ ACMD_FUNC(heal) } if ( hp < 0 && sp <= 0 ) { - status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); + status_damage(NULL, &sd->bl, -hp, -sp, 0, 0, 0); clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, DMG_ENDURE, 0, false); clif_displaymessage(fd, msg_txt(sd,156)); // HP or/and SP modified. return 0; @@ -1320,7 +1320,7 @@ ACMD_FUNC(heal) if (hp > 0) status_heal(&sd->bl, hp, 0, 0); else { - status_damage(NULL, &sd->bl, -hp, 0, 0, 0); + status_damage(NULL, &sd->bl, -hp, 0, 0, 0, 0); clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, DMG_ENDURE, 0, false); } } @@ -1329,7 +1329,7 @@ ACMD_FUNC(heal) if (sp > 0) status_heal(&sd->bl, 0, sp, 0); else - status_damage(NULL, &sd->bl, 0, -sp, 0, 0); + status_damage(NULL, &sd->bl, 0, -sp, 0, 0, 0); } clif_displaymessage(fd, msg_txt(sd,156)); // HP or/and SP modified. @@ -3490,6 +3490,28 @@ ACMD_FUNC(spiritball) return 0; } +ACMD_FUNC(soulball) +{ + uint32 max_soulballs = min(ARRAYLENGTH(sd->soul_timer), 0x7FFF); + int number; + nullpo_retr(-1, sd); + + if (!message || !*message || (number = atoi(message)) < 0 || number > max_soulballs) { + char msg[CHAT_SIZE_MAX]; + safesnprintf(msg, sizeof(msg), "Usage: @soulball ", max_soulballs); + clif_displaymessage(fd, msg); + return -1; + } + + if (sd->soulball > 0) + pc_delsoulball(sd, sd->soulball, 1); + sd->soulball = number; + clif_soulball(sd); + // no message, player can see the difference + + return 0; +} + /*========================================== * *------------------------------------------*/ @@ -10289,6 +10311,7 @@ void atcommand_basecommands(void) { ACMD_DEF(questskill), ACMD_DEF(lostskill), ACMD_DEF(spiritball), + ACMD_DEF(soulball), ACMD_DEF(party), ACMD_DEF(guild), ACMD_DEF(breakguild), diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 48931501fe..81e1b0d88f 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -268,9 +268,9 @@ struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int void battle_damage(struct block_list *src, struct block_list *target, int64 damage, t_tick delay, uint16 skill_lv, uint16 skill_id, enum damage_lv dmg_lv, unsigned short attack_type, bool additional_effects, t_tick tick, bool isspdamage) { map_freeblock_lock(); if (isspdamage) - status_fix_spdamage(src, target, damage, delay); + status_fix_spdamage(src, target, damage, delay, skill_id); else - status_fix_damage(src, target, damage, delay); // We have to separate here between reflect damage and others [icescope] + status_fix_damage(src, target, damage, delay, skill_id); // We have to separate here between reflect damage and others [icescope] if (attack_type && !status_isdead(target) && additional_effects) skill_additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, tick); if (dmg_lv > ATK_BLOCK && attack_type) @@ -316,7 +316,7 @@ TIMER_FUNC(battle_delay_damage_sub){ battle_damage(src, target, dat->damage, dat->delay, dat->skill_lv, dat->skill_id, dat->dmg_lv, dat->attack_type, dat->additional_effects, tick, dat->isspdamage); } else if( !src && dat->skill_id == CR_REFLECTSHIELD ) { // it was monster reflected damage, and the monster died, we pass the damage to the character as expected map_freeblock_lock(); - status_fix_damage(target, target, dat->damage, dat->delay); + status_fix_damage(target, target, dat->damage, dat->delay, dat->skill_id); map_freeblock_unlock(); } } @@ -576,6 +576,22 @@ int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 d damage += (int64)(damage * tsc->data[SC_ANTI_M_BLAST]->val2 / 100); #endif break; + case ELE_DARK: + if (tsc->data[SC_SOULCURSE]) { + if (status_get_class_(target) == CLASS_BOSS) +#ifdef RENEWAL + ratio += 20; +#else + damage += (int64)(damage * 20 / 100); +#endif + else +#ifdef RENEWAL + ratio += 100; +#else + damage *= 2; +#endif + } + break; } } @@ -1057,7 +1073,7 @@ bool battle_check_sc(struct block_list *src, struct block_list *target, struct s int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int64 damage,uint16 skill_id,uint16 skill_lv) { struct map_session_data *sd = NULL; - struct status_change *sc; + struct status_change *sc, *tsc; struct status_change_entry *sce; int div_ = d->div_, flag = d->flag; @@ -1096,12 +1112,19 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam if (sc && sc->data[SC_MAXPAIN]) return 0; + switch (skill_id) { #ifndef RENEWAL - if (skill_id == PA_PRESSURE - || skill_id == HW_GRAVITATION - ) - return damage; //These skills bypass everything else. + case PA_PRESSURE: + case HW_GRAVITATION: #endif + case SP_SOULEXPLOSION: + return damage; //These skills bypass everything else. + } + + // Nothing can reduce the damage, but Safety Wall and Millennium Shield can block it completely. + // So can defense sphere's but what the heck is that??? [Rytech] + if (skill_id == SJ_NOVAEXPLOSING && !(sc && (sc->data[SC_SAFETYWALL] || sc->data[SC_MILLENNIUMSHIELD]))) + return damage; if( sc && sc->count ) { // SC_* that reduce damage to 0. #ifdef RENEWAL @@ -1109,7 +1132,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam #else if (sc->data[SC_BASILICA] #endif - && !status_bl_has_mode(src,MD_STATUS_IMMUNE) ) { + && !status_bl_has_mode(src,MD_STATUS_IMMUNE) && skill_id != SP_SOULEXPLOSION ) { d->dmg_lv = ATK_BLOCK; return 0; } @@ -1137,7 +1160,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam if (!battle_check_sc(src, bl, sc, d, damage, skill_id, skill_lv)) return 0; - if (sc->data[SC__MANHOLE] || (src->type == BL_PC && sc->data[SC_KINGS_GRACE])) { + if (sc->data[SC__MANHOLE] || (src->type == BL_PC && sc->data[SC_KINGS_GRACE]) || sc->data[SC_GRAVITYCONTROL]) { d->dmg_lv = ATK_BLOCK; return 0; } @@ -1481,6 +1504,26 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam status_change_end(bl, SC_TUNAPARTY, INVALID_TIMER); } + if ((sce = sc->data[SC_DIMENSION1]) && damage > 0) { + sce->val2 -= (int)cap_value(damage, INT_MIN, INT_MAX); + if (sce->val2 >= 0) + damage = 0; + else + damage = -sce->val2; + if (sce->val2 <= 0) + status_change_end(bl, SC_DIMENSION1, INVALID_TIMER); + } + + if ((sce = sc->data[SC_DIMENSION2]) && damage > 0) { + sce->val2 -= (int)cap_value(damage, INT_MIN, INT_MAX); + if (sce->val2 >= 0) + damage = 0; + else + damage = -sce->val2; + if (sce->val2 <= 0) + status_change_end(bl, SC_DIMENSION2, INVALID_TIMER); + } + if( sc->data[SC_MEIKYOUSISUI] && rnd()%100 < 40 ) // custom value damage = 0; @@ -1527,6 +1570,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam //SC effects from caster side. sc = status_get_sc(src); + tsc = status_get_sc(src); if (sc && sc->count) { if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) @@ -1579,6 +1623,19 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam } } //End of caster SC_ check + if (tsc && tsc->count) { + struct map_session_data *tsd = (struct map_session_data *)src; + + if (tsc->data[SC_INVINCIBLE] && !tsc->data[SC_INVINCIBLEOFF]) + damage += damage * 75 / 100; + if (tsd && (sce = tsc->data[SC_SOULREAPER])) { + if (rnd()%100 < sce->val2 && tsd->soulball < MAX_SOUL_BALL) { + clif_specialeffect(src, 1208, AREA); + pc_addsoulball(tsd, 0, 5 + 3 * pc_checkskill(tsd, SP_SOULENERGY)); + } + } + } + //PK damage rates if (battle_config.pk_mode && sd && bl->type == BL_PC && damage && map_getmapflag(bl->m, MF_PVP)) { if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] @@ -2880,6 +2937,9 @@ static int battle_get_weapon_element(struct Damage* wd, struct block_list *src, if (sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 4) element = ELE_HOLY; break; + case SJ_PROMINENCEKICK: + element = ELE_FIRE; + break; case RL_H_MINE: if (sd && sd->flicker) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER element = ELE_FIRE; @@ -4424,8 +4484,12 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * case KO_SETSUDAN: skillratio += 100 * (skill_lv - 1); RE_LVL_DMOD(100); - if(tsc && tsc->data[SC_SPIRIT]) - skillratio += 200 * tsc->data[SC_SPIRIT]->val1; + if (tsc) { + struct status_change_entry *sce; + + if ((sce = tsc->data[SC_SPIRIT]) || (sce = tsc->data[SC_SOULGOLEM]) || (sce = tsc->data[SC_SOULSHADOW]) || (sce = tsc->data[SC_SOULFALCON]) || (sce = tsc->data[SC_SOULFAIRY])) // Bonus damage added when target is soul linked. + skillratio += 200 * sce->val1; + } break; case KO_BAKURETSU: skillratio += -100 + (sd ? pc_checkskill(sd,NJ_TOBIDOUGU) : 1) * (50 + sstatus->dex / 4) * skill_lv * 4 / 10; @@ -4540,6 +4604,34 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list * if (sd && pc_checkskill(sd, SU_SPIRITOFLIFE)) skillratio += skillratio * status_get_hp(src) / status_get_max_hp(src); break; + case SJ_FULLMOONKICK: + skillratio += 1000 + 100 * skill_lv; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_LIGHTOFMOON]) + skillratio += skillratio * sc->data[SC_LIGHTOFMOON]->val2 / 100; + break; + case SJ_NEWMOONKICK: + skillratio += 600 + 100 * skill_lv; + break; + case SJ_STAREMPEROR: + skillratio += 700 + 200 * skill_lv; + break; + case SJ_SOLARBURST: + skillratio += 900 + 220 * skill_lv; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_LIGHTOFSUN]) + skillratio += skillratio * sc->data[SC_LIGHTOFSUN]->val2 / 100; + break; + case SJ_PROMINENCEKICK: + skillratio += 50 + 50 * skill_lv; + break; + case SJ_FALLINGSTAR_ATK: + case SJ_FALLINGSTAR_ATK2: + skillratio += 100 * skill_lv; + RE_LVL_DMOD(100); + if (sc && sc->data[SC_LIGHTOFSTAR]) + skillratio += skillratio * sc->data[SC_LIGHTOFSTAR]->val2 / 100; + break; } return skillratio; } @@ -5245,7 +5337,7 @@ static void battle_calc_weapon_final_atk_modifiers(struct Damage* wd, struct blo ) { ATK_RATER(wd->damage, 50) - status_fix_damage(target,src,wd->damage,clif_damage(target,src,gettick(),0,0,wd->damage,0,DMG_NORMAL,0,false)); + status_fix_damage(target,src,wd->damage,clif_damage(target,src,gettick(),0,0,wd->damage,0,DMG_NORMAL,0,false),ST_REJECTSWORD); clif_skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_REJECTSWORD]->val1,1); if( --(tsc->data[SC_REJECTSWORD]->val3) <= 0 ) status_change_end(target, SC_REJECTSWORD, INVALID_TIMER); @@ -5262,8 +5354,8 @@ static void battle_calc_weapon_final_atk_modifiers(struct Damage* wd, struct blo clif_skill_damage(target, src, gettick(), status_get_amotion(src), 0, rdamage, 1, SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1, DMG_SINGLE); // This is how official does clif_damage(src, target, gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, DMG_NORMAL, 0, false); - status_damage(target, src, rdamage, 0, 0, 0); - status_damage(src, target, rdamage/10, 0, 0, 1); + status_damage(target, src, rdamage, 0, 0, 0, 0); + status_damage(src, target, rdamage/10, 0, 0, 1, 0); status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER); } @@ -5983,6 +6075,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list MATK_ADD(sstatus->matk_min); } + if (sd) { // Soul energy spheres adds MATK. + MATK_ADD(3*sd->soulball); + } + if (nk[NK_SPLASHSPLIT]) { // Divide MATK in case of multiple targets skill if (mflag>0) ad.damage /= mflag; @@ -6407,6 +6503,23 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list i = cap_value(i, 1, 4); skillratio = 2500 + ((skill_lv - i + 1) * 500); break; + case SP_CURSEEXPLOSION: + if (tsc && tsc->data[SC_SOULCURSE]) + skillratio += 1400 + 200 * skill_lv; + else + skillratio += 300 + 100 * skill_lv; + break; + case SP_SPA: + skillratio += 400 + 250 * skill_lv; + RE_LVL_DMOD(100); + break; + case SP_SHA: + skillratio += -100 + 5 * skill_lv; + break; + case SP_SWHOO: + skillratio += 1000 + 200 * skill_lv; + RE_LVL_DMOD(100); + break; } if (sc) {// Insignia's increases the damage of offensive magic by a fixed percentage depending on the element. @@ -6880,6 +6993,16 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case SU_SV_ROOTTWIST_ATK: md.damage = 100; break; + case SP_SOULEXPLOSION: + md.damage = tstatus->hp * (20 + 10 * skill_lv) / 100; + break; + case SJ_NOVAEXPLOSING: + // (Base ATK + Weapon ATK) * Ratio + md.damage = (sstatus->batk + sstatus->rhw.atk) * (200 + 100 * skill_lv) / 100; + + // Additional Damage + md.damage += sstatus->max_hp / (6 - min(5, skill_lv)) + status_get_max_sp(src) * (2 * skill_lv); + break; } if (nk[NK_SPLASHSPLIT]) { // Divide ATK among targets @@ -7311,7 +7434,7 @@ int battle_damage_area(struct block_list *bl, va_list ap) { if( amotion ) battle_delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true,false); else - status_fix_damage(src,bl,damage,0); + status_fix_damage(src,bl,damage,0,LG_REFLECTDAMAGE); clif_damage(bl,bl,tick,amotion,dmotion,damage,1,DMG_ENDURE,0,false); skill_additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); map_freeblock_unlock(); @@ -7397,6 +7520,8 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t status_change_end(src, SC_CLOAKING, INVALID_TIMER); else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4 & 2)) status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); + else if (sc->data[SC_NEWMOON] && --(sc->data[SC_NEWMOON]->val2) <= 0) + status_change_end(src, SC_NEWMOON, INVALID_TIMER); } if (tsc && tsc->data[SC_AUTOCOUNTER] && status_check_skilluse(target, src, KN_AUTOCOUNTER, 1)) { uint8 dir = map_calc_dir(target,src->x,src->y); @@ -7615,7 +7740,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } clif_damage(d_bl, d_bl, gettick(), wd.amotion, wd.dmotion, damage, 1, DMG_NORMAL, 0, false); - status_fix_damage(NULL, d_bl, damage, 0); + status_fix_damage(NULL, d_bl, damage, 0, CR_DEVOTION); } } else @@ -7634,7 +7759,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (e_bl && !status_isdead(e_bl)) { clif_damage(e_bl, e_bl, tick, 0, 0, damage, wd.div_, DMG_NORMAL, 0, false); - status_fix_damage(NULL, e_bl, damage, 0); + status_fix_damage(NULL, e_bl, damage, 0, EL_WATER_SCREEN); } } } @@ -7737,7 +7862,14 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t clif_status_change(src, EFST_POSTDELAY, 1, skill_delayfix(src, r_skill, r_lv), 0, 0, 1); } } - + if (wd.flag&BF_WEAPON && sc && sc->data[SC_FALLINGSTAR] && rand()%100 < sc->data[SC_FALLINGSTAR]->val2) { + if (sd) + sd->state.autocast = 1; + if (status_charge(src, 0, skill_get_sp(SJ_FALLINGSTAR_ATK, sc->data[SC_FALLINGSTAR]->val1))) + skill_castend_nodamage_id(src, src, SJ_FALLINGSTAR_ATK, sc->data[SC_FALLINGSTAR]->val1, tick, flag); + if (sd) + sd->state.autocast = 0; + } if (wd.flag & BF_WEAPON && src != target && damage > 0) { if (battle_config.left_cardfix_to_right) battle_drain(sd, target, wd.damage, wd.damage, tstatus->race, tstatus->class_); diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 373c6eea43..44a6aec285 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -1387,6 +1387,29 @@ static void clif_spiritcharm_single(int fd, struct map_session_data *sd) WFIFOSET(fd, packet_len(0x08cf)); } + +/// Notifies the client of an object's souls. +/// Note: Spirit spheres and Soul spheres work on +/// seprate systems officially, but both send out +/// the same packet which leads to confusion on how +/// much soul energy a Soul Reaper acturally has +/// should the player also have spirit spheres. +/// They will likely create a new packet for this soon +/// to seprate the animations for spirit and soul spheres. +/// For now well use this and replace it later when possible. [Rytech] +/// +/// 01d0 .L .W (ZC_SPIRITS) +/// 01e1 .L .W (ZC_SPIRITS2) +static void clif_soulball_single(int fd, struct map_session_data *sd) +{ + WFIFOHEAD(fd, packet_len(0x1d0)); + WFIFOW(fd,0)=0x1d0; + WFIFOL(fd,2)=sd->bl.id; + WFIFOW(fd,6)=sd->soulball; + WFIFOSET(fd, packet_len(0x1d0)); +} + + /*========================================== * Run when player changes map / refreshes * Tells its client to display all weather settings being used by this map @@ -1476,6 +1499,8 @@ int clif_spawn(struct block_list *bl) if (sd->spiritball > 0) clif_spiritball(&sd->bl); + if (sd->soulball > 0) + clif_soulball(sd); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif_specialeffect(bl,EF_GIANTBODY2,AREA); else if(sd->state.size==SZ_MEDIUM) @@ -4608,6 +4633,33 @@ void clif_storageclose(struct map_session_data* sd) WFIFOSET(fd,packet_len(0xf8)); } + +/// Notifies clients in an area of an object's souls. +/// Note: Spirit spheres and Soul spheres work on +/// seprate systems officially, but both send out +/// the same packet which leads to confusion on how +/// much soul energy a Soul Reaper acturally has +/// should the player also have spirit spheres. +/// They will likely create a new packet for this soon +/// to seprate the animations for spirit and soul spheres. +/// For now well use this and replace it later when possible. [Rytech] +/// +/// 01d0 .L .W (ZC_SPIRITS) +/// 01e1 .L .W (ZC_SPIRITS2) +void clif_soulball(struct map_session_data *sd) +{ + unsigned char buf[8]; + + nullpo_retv(sd); + + WBUFW(buf,0)=0x1d0; + WBUFL(buf,2)=sd->bl.id; + WBUFW(buf,6)=sd->soulball; + clif_send(buf,packet_len(0x1d0),&sd->bl,AREA); + return; +} + + /*========================================== * Server tells 'sd' player client the abouts of 'dstsd' player *------------------------------------------*/ @@ -4629,6 +4681,8 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d clif_spiritball_single(sd->fd, dstsd); if (dstsd->spiritcharm_type != CHARM_TYPE_NONE && dstsd->spiritcharm > 0) clif_spiritcharm_single(sd->fd, dstsd); + if (dstsd->soulball > 0) + clif_soulball_single(sd->fd, dstsd); if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround pc_has_permission(sd, PC_PERM_VIEW_HPMETER) @@ -6027,6 +6081,10 @@ void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t nullpo_retv(bl); + // Statuses with an infinite duration, but still needs a duration sent to display properly. + if (type == EFST_LUNARSTANCE || type == EFST_UNIVERSESTANCE || type == EFST_SUNSTANCE || type == EFST_STARSTANCE) + tick = 200; + #if PACKETVER >= 20120618 if (flag && battle_config.display_status_timers) WBUFW(buf,0) = 0x983; @@ -9503,6 +9561,8 @@ void clif_refresh(struct map_session_data *sd) clif_spiritball_single(sd->fd, sd); if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) clif_spiritcharm_single(sd->fd, sd); + if (sd->soulball) + clif_soulball_single(sd->fd, sd); if (sd->vd.cloth_color) clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); if (sd->vd.body_style) @@ -10705,7 +10765,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if(!sd->state.autotrade && mapdata->flag[MF_LOADEVENT]) // Lance npc_script_event(sd, NPCE_LOADMAP); - if (pc_checkskill(sd, SG_DEVIL) && pc_is_maxjoblv(sd)) + if (pc_checkskill(sd, SG_DEVIL) && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd))) clif_status_load(&sd->bl, EFST_DEVIL1, 1); //blindness [Komurka] if (sd->sc.opt2) //Client loses these on warp. @@ -10985,7 +11045,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd) { /* Rovert's prevent logout option fixed [Valaris] */ //int type = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0]); - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] && + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] && !sd->sc.data[SC_NEWMOON] && (!battle_config.prevent_logout || sd->canlog_tick == 0 || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { set_eof(fd); @@ -11221,7 +11281,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, (sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) || sd->sc.data[SC_BLADESTOP] || sd->sc.data[SC__MANHOLE] || - sd->sc.data[SC_SUHIDE] )) + sd->sc.data[SC_SUHIDE] || + sd->sc.data[SC_GRAVITYCONTROL])) return; if(action_type != 0x00 && action_type != 0x07) @@ -11348,7 +11409,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) break; case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] && + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC_SUHIDE] && !sd->sc.data[SC_NEWMOON] && (!battle_config.prevent_logout || sd->canlog_tick == 0 || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { //Send to char-server for character selection. pc_damage_log_clear(sd,0); diff --git a/src/map/clif.hpp b/src/map/clif.hpp index a621ed9941..b52761d30b 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -714,6 +714,7 @@ void clif_skillunit_update(struct block_list* bl); void clif_autospell(struct map_session_data *sd,uint16 skill_lv); void clif_devotion(struct block_list *src, struct map_session_data *tsd); void clif_spiritball(struct block_list *bl); +void clif_soulball(struct map_session_data *sd); void clif_combo_delay(struct block_list *bl,t_tick wait); void clif_bladestop(struct block_list *src, int dst_id, int active); void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target); diff --git a/src/map/map.cpp b/src/map/map.cpp index 0aee3ce7cd..0f196201ba 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -2146,6 +2146,10 @@ int map_quit(struct map_session_data *sd) { status_change_end(&sd->bl, SC_GLASTHEIM_STATE, INVALID_TIMER); status_change_end(&sd->bl, SC_GLASTHEIM_ITEMDEF, INVALID_TIMER); status_change_end(&sd->bl, SC_GLASTHEIM_HPSP, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULGOLEM, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULSHADOW, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULFALCON, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULFAIRY, INVALID_TIMER); } } diff --git a/src/map/pc.cpp b/src/map/pc.cpp index bd310e5eea..7c36b206bf 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -505,6 +505,115 @@ void pc_delspiritball(struct map_session_data *sd,int count,int type) } } +static TIMER_FUNC(pc_soulball_timer) +{ + struct map_session_data *sd; + + if ((sd = (struct map_session_data *)map_id2sd(id)) == nullptr || sd->bl.type != BL_PC) + return 1; + + if (sd->soulball <= 0) { + ShowError("pc_soulball_timer: %d soulball's available. (aid=%d tid=%d)\n", sd->soulball, sd->status.account_id, tid); + sd->soulball = 0; + return 0; + } + + int i; + + ARR_FIND(0, sd->soulball, i, sd->soul_timer[i] == tid); + if (i == sd->soulball) { + ShowError("pc_soulball_timer: timer not found (aid=%d tid=%d)\n", sd->status.account_id, tid); + return 0; + } + + sd->soulball--; + if (i != sd->soulball) + memmove(sd->soul_timer + i, sd->soul_timer + i + 1, (sd->soulball - i) * sizeof(int)); + sd->soul_timer[sd->soulball] = INVALID_TIMER; + clif_soulball(sd); + + return 0; +} + +/** + * Adds a soulball to player for 'interval' ms + * @param sd: Player data + * @param interval: Duration + * @param max: Max amount of soulballs + */ +int pc_addsoulball(struct map_session_data *sd, int interval, int max) +{ + nullpo_ret(sd); + + max = min(max, MAX_SOUL_BALL); + sd->soulball = cap_value(sd->soulball, 0, MAX_SOUL_BALL); + + if (sd->soulball && sd->soulball >= max) { + if (sd->soul_timer[0] != INVALID_TIMER) + delete_timer(sd->soul_timer[0], pc_soulball_timer); + sd->soulball--; + if (sd->soulball != 0) + memmove(sd->soul_timer + 0, sd->soul_timer + 1, (sd->soulball) * sizeof(int)); + sd->soul_timer[sd->soulball] = INVALID_TIMER; + } + + if (interval > 0) { + int tid = add_timer(gettick() + interval, pc_soulball_timer, sd->bl.id, 0), i; + + ARR_FIND(0, sd->soulball, i, sd->soul_timer[i] == INVALID_TIMER || DIFF_TICK(get_timer(tid)->tick, get_timer(sd->soul_timer[i])->tick) < 0); + if (i != sd->soulball) + memmove(sd->soul_timer + i + 1, sd->soul_timer + i, (sd->soulball - i) * sizeof(int)); + sd->soul_timer[i] = tid; + } + + sd->soulball++; + clif_soulball(sd); + + return 0; +} + +/** + * Removes number of soulball from player + * @param sd: Player data + * @param count: Amount to remove + * @param type: 1 = doesn't give client effect + */ +int pc_delsoulball(struct map_session_data *sd, int count, int type) +{ + nullpo_ret(sd); + + if (sd->soulball <= 0) { + sd->soulball = 0; + return 0; + } + + if (count <= 0) + return 0; + + if (count > sd->soulball) + count = sd->soulball; + sd->soulball -= count; + if (count > MAX_SKILL_LEVEL) + count = MAX_SKILL_LEVEL; + + for (int i = 0; i < count; i++) { + if (sd->soul_timer[i] != INVALID_TIMER) { + delete_timer(sd->soul_timer[i], pc_soulball_timer); + sd->soul_timer[i] = INVALID_TIMER; + } + } + + for (int i = count; i < MAX_SKILL_LEVEL; i++) { + sd->soul_timer[i - count] = sd->soul_timer[i]; + sd->soul_timer[i] = INVALID_TIMER; + } + + if (!type) + clif_soulball(sd); + + return 0; +} + /** * Increases a player's fame points and displays a notice to him * @param sd Player @@ -1383,6 +1492,8 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ for(i = 0; i < MAX_SPIRITBALL; i++) sd->spirit_timer[i] = INVALID_TIMER; + for (i = 0; i < MAX_SOUL_BALL; i++) + sd->soul_timer[i] = INVALID_TIMER; if (battle_config.item_auto_get) sd->state.autoloot = 10000; @@ -6016,6 +6127,13 @@ bool pc_memo(struct map_session_data* sd, int pos) * @return player skill cooldown */ int pc_get_skillcooldown(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { + if (skill_id == SJ_NOVAEXPLOSING) { + struct status_change *sc = status_get_sc(&sd->bl); + + if (sc && sc->data[SC_DIMENSION]) + return 0; + } + int cooldown = skill_get_cooldown(skill_id, skill_lv); if (cooldown == 0) @@ -6900,7 +7018,7 @@ int pc_checkjoblevelup(struct map_session_data *sd) clif_updatestatus(sd,SP_SKILLPOINT); status_calc_pc(sd,SCO_FORCE); clif_misceffect(&sd->bl,1); - if (pc_checkskill(sd, SG_DEVIL) && pc_is_maxbaselv(sd)) + if (pc_checkskill(sd, SG_DEVIL) && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)) ) clif_status_change(&sd->bl, EFST_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. npc_script_event(sd, NPCE_JOBLVUP); @@ -7456,6 +7574,8 @@ void pc_skillup(struct map_session_data *sd,uint16 skill_id) clif_updatestatus(sd,SP_SKILLPOINT); if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ clif_updatestatus(sd,SP_CARTINFO); + if (pc_checkskill(sd, SG_DEVIL) && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd))) + clif_status_change(&sd->bl, EFST_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown clif_skillinfoblock(sd); } @@ -7684,7 +7804,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( pc_is_taekwon_ranker(sd) ) return 0; - if( pc_checkskill(sd, SG_DEVIL) && pc_is_maxjoblv(sd) ) + if( pc_checkskill(sd, SG_DEVIL) && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd)) ) clif_status_load(&sd->bl, EFST_DEVIL1, 0); //Remove perma blindness due to skill-reset. [Skotlex] i = sd->sc.option; if( i&OPTION_RIDING && pc_checkskill(sd, KN_RIDING) ) @@ -7802,7 +7922,7 @@ int pc_resethate(struct map_session_data* sd) int i; nullpo_ret(sd); - for (i=0; i<3; i++) + for (i=0; ihate_mob[i] = -1; pc_setglobalreg(sd, add_str(sg_info[i].hate_var), 0); @@ -8030,6 +8150,27 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) sd->devotion[k] = 0; } } + + for (k = 0; k < MAX_STELLAR_MARKS; k++) { + if (sd->stellar_mark[k]) { + struct map_session_data *smarksd = map_id2sd(sd->stellar_mark[k]); + + if (smarksd) + status_change_end(&smarksd->bl, SC_FLASHKICK, INVALID_TIMER); + sd->stellar_mark[k] = 0; + } + } + + for (k = 0; k < MAX_UNITED_SOULS; k++) { + if (sd->united_soul[k]) { + struct map_session_data *usoulsd = map_id2sd(sd->united_soul[k]); + + if (usoulsd) + status_change_end(&usoulsd->bl, SC_SOULUNITY, INVALID_TIMER); + sd->united_soul[k] = 0; + } + } + if(sd->shadowform_id) { //if we were target of shadowform status_change_end(map_id2bl(sd->shadowform_id), SC__SHADOWFORM, INVALID_TIMER); sd->shadowform_id = 0; //should be remove on status end anyway @@ -8088,6 +8229,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) if ( sd->spiritball !=0 ) pc_delspiritball(sd,sd->spiritball,0); + if (sd->soulball != 0) + pc_delsoulball(sd, sd->soulball, 0); if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0) pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type); @@ -13273,6 +13416,7 @@ void do_init_pc(void) { add_timer_func_list(pc_calc_pvprank_timer, "pc_calc_pvprank_timer"); add_timer_func_list(pc_autosave, "pc_autosave"); add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); + add_timer_func_list(pc_soulball_timer, "pc_soulball_timer"); add_timer_func_list(pc_follow_timer, "pc_follow_timer"); add_timer_func_list(pc_endautobonus, "pc_endautobonus"); add_timer_func_list(pc_spiritcharm_timer, "pc_spiritcharm_timer"); diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 2b51c959c5..f18cf6a469 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -35,6 +35,9 @@ enum sc_type : int16; #define MAX_SPIRITBALL 15 /// Max spirit balls #define MAX_DEVOTION 5 /// Max Devotion slots #define MAX_SPIRITCHARM 10 /// Max spirit charms +#define MAX_SOUL_BALL 20 /// Max soul ball +#define MAX_STELLAR_MARKS 5 /// Max stellar marks +#define MAX_UNITED_SOULS 12 /// Max united souls #define LANGTYPE_VAR "#langtype" #define CASHPOINT_VAR "#CASHPOINTS" @@ -534,12 +537,16 @@ struct map_session_data { short spiritcharm; //No. of spirit int spiritcharm_type; //Spirit type int spiritcharm_timer[MAX_SPIRITCHARM]; + int8 soulball, soulball_old; + int soul_timer[MAX_SOUL_BALL]; unsigned char potion_success_counter; //Potion successes in row counter unsigned char mission_count; //Stores the bounty kill count for TK_MISSION short mission_mobid; //Stores the target mob_id for TK_MISSION int die_counter; //Total number of times you've died int devotion[MAX_DEVOTION]; //Stores the account IDs of chars devoted to. + int stellar_mark[MAX_STELLAR_MARKS]; // Stores the account ID's of character's with a stellar mark. + int united_soul[MAX_UNITED_SOULS]; // Stores the account ID's of character's who's soul is united. int trade_partner; struct s_deal { @@ -1292,6 +1299,9 @@ void pc_delinvincibletimer(struct map_session_data* sd); void pc_addspiritball(struct map_session_data *sd,int interval,int max); void pc_delspiritball(struct map_session_data *sd,int count,int type); +int pc_addsoulball(struct map_session_data *sd,int interval,int max); +int pc_delsoulball(struct map_session_data *sd,int count,int type); + void pc_addfame(struct map_session_data *sd,int count); unsigned char pc_famerank(uint32 char_id, int job); bool pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl); diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 2d0171ff73..352dde1699 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -1546,6 +1546,35 @@ export_constant(SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT); export_constant(SC_ADAPTATION); export_constant(SC_BASILICA_CELL); + export_constant(SC_LIGHTOFMOON); + export_constant(SC_LIGHTOFSUN); + export_constant(SC_LIGHTOFSTAR); + export_constant(SC_LUNARSTANCE); + export_constant(SC_UNIVERSESTANCE); + export_constant(SC_SUNSTANCE); + export_constant(SC_FLASHKICK); + export_constant(SC_NEWMOON); + export_constant(SC_STARSTANCE); + export_constant(SC_DIMENSION); + export_constant(SC_DIMENSION1); + export_constant(SC_DIMENSION2); + export_constant(SC_CREATINGSTAR); + export_constant(SC_FALLINGSTAR); + export_constant(SC_NOVAEXPLOSING); + export_constant(SC_GRAVITYCONTROL); + export_constant(SC_SOULCOLLECT); + export_constant(SC_SOULREAPER); + export_constant(SC_SOULUNITY); + export_constant(SC_SOULSHADOW); + export_constant(SC_SOULFAIRY); + export_constant(SC_SOULFALCON); + export_constant(SC_SOULGOLEM); + export_constant(SC_SOULDIVISION); + export_constant(SC_SOULENERGY); + export_constant(SC_USE_SKILL_SP_SPA); + export_constant(SC_USE_SKILL_SP_SHA); + export_constant(SC_SP_SHA); + export_constant(SC_SOULCURSE); #ifdef RENEWAL export_constant(SC_EXTREMITYFIST2); #endif @@ -7689,6 +7718,7 @@ export_constant(UNT_FIRE_RAIN); export_constant(UNT_CATNIPPOWDER); export_constant(UNT_NYANGGRASS); + export_constant(UNT_CREATINGSTAR); export_constant(UNT_GD_LEADERSHIP); export_constant(UNT_GD_GLORYWOUNDS); export_constant(UNT_GD_SOULCOLD); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index d646b79814..de2a16aab8 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -1633,6 +1633,13 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 status_change_end(bl, SC_KAAHI, INVALID_TIMER); status_change_end(bl, SC_ONEHAND, INVALID_TIMER); status_change_end(bl, SC_ASPDPOTION2, INVALID_TIMER); + // New soul links confirmed to not dispell with this skill + // but thats likely a bug since soul links can't stack and + // soul cutter skill works on them. So ill add this here for now. [Rytech] + status_change_end(bl, SC_SOULGOLEM, INVALID_TIMER); + status_change_end(bl, SC_SOULSHADOW, INVALID_TIMER); + status_change_end(bl, SC_SOULFALCON, INVALID_TIMER); + status_change_end(bl, SC_SOULFAIRY, INVALID_TIMER); } break; case TK_TURNKICK: @@ -1905,8 +1912,13 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case KO_JYUMONJIKIRI: sc_start(src,bl,SC_JYUMONJIKIRI,100,skill_lv,skill_get_time(skill_id,skill_lv)); break; - case KO_SETSUDAN: - status_change_end(bl,SC_SPIRIT,INVALID_TIMER); + case SP_SOULEXPLOSION: + case KO_SETSUDAN: // Remove soul link when hit. + status_change_end(bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(bl, SC_SOULGOLEM, INVALID_TIMER); + status_change_end(bl, SC_SOULSHADOW, INVALID_TIMER); + status_change_end(bl, SC_SOULFALCON, INVALID_TIMER); + status_change_end(bl, SC_SOULFAIRY, INVALID_TIMER); break; case KO_MAKIBISHI: sc_start(src,bl, SC_STUN, 10 * skill_lv, skill_lv, skill_get_time2(skill_id,skill_lv)); @@ -2027,6 +2039,10 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case SC_RECOGNIZEDSPELL: case SC_CHASEWALK2: case SC_BITE: case SC_ACTIVE_MONSTER_TRANSFORM: case SC_DORAM_BUF_01: case SC_DORAM_BUF_02: case SC_SPORE_EXPLOSION: + case SC_NEWMOON: case SC_FLASHKICK: case SC_NOVAEXPLOSING: + case SC_SOULUNITY: case SC_SOULSHADOW: case SC_SOULFAIRY: + case SC_SOULFALCON: case SC_SOULGOLEM: case SC_USE_SKILL_SP_SPA: + case SC_USE_SKILL_SP_SHA: case SC_SP_SHA: #ifdef RENEWAL case SC_EXTREMITYFIST2: #endif @@ -2096,6 +2112,18 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case SU_LUNATICCARROTBEAT2: sc_start(src, bl, SC_STUN, 20, skill_lv, skill_get_time2(skill_id, skill_lv)); break; + case SJ_FULLMOONKICK: + sc_start(src, bl, SC_BLIND, 15 + 5 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case SJ_STAREMPEROR: + sc_start(src, bl, SC_SILENCE, 50 + 10 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case SP_CURSEEXPLOSION: + status_change_end(bl, SC_SOULCURSE, INVALID_TIMER); + break; + case SP_SHA: + sc_start(src, bl, SC_SP_SHA, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; } //end switch skill_id if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) @@ -2449,6 +2477,15 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * } } break; + case SP_SPA: + sc_start(src, src, SC_USE_SKILL_SP_SPA, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + case SP_SHA: + sc_start(src, src, SC_USE_SKILL_SP_SHA, 100, skill_lv, skill_get_time2(skill_id, skill_lv)); + break; + case SP_SWHOO: + sc_start(src, src, SC_USE_SKILL_SP_SHA, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; } if(sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && @@ -3079,6 +3116,10 @@ void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_li if (pc_checkskill(sd, SR_TIGERCANNON) > 0 || pc_checkskill(sd, SR_GATEOFHELL) > 0) duration = 1; break; + case SJ_PROMINENCEKICK: + if (pc_checkskill(sd, SJ_SOLARBURST) > 0) + duration = 1; + break; } } else { //other @@ -3458,7 +3499,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * nbl = battle_getenemyarea(bl,bl->x,bl->y,2,BL_CHAR,bl->id); if( nbl ){ // Only one target is chosen. damage = damage / 2; // Deflect half of the damage to a target nearby - clif_skill_damage(bl, nbl, tick, status_get_amotion(src), 0, status_fix_damage(bl,nbl,damage,0), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, DMG_SINGLE); + clif_skill_damage(bl, nbl, tick, status_get_amotion(src), 0, status_fix_damage(bl,nbl,damage,0,0), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, DMG_SINGLE); } } @@ -3633,12 +3674,22 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * break; case SU_LUNATICCARROTBEAT: case SU_LUNATICCARROTBEAT2: + case SP_CURSEEXPLOSION: + case SP_SPA: + case SP_SHA: if (dmg.div_ < 2) type = DMG_SPLASH; if (!(flag&SD_ANIMATION)) clif_skill_nodamage(dsrc, bl, skill_id, skill_lv, 1); dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, dmg_type); break; + case SJ_FALLINGSTAR_ATK: + case SJ_FALLINGSTAR_ATK2: + dmg.dmotion = clif_skill_damage(src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, DMG_MULTI_HIT); + break; + case SJ_NOVAEXPLOSING: + dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -2, DMG_SINGLE); + break; case AB_DUPLELIGHT_MELEE: case AB_DUPLELIGHT_MAGIC: dmg.amotion = 300;/* makes the damage value not overlap with previous damage (when displayed by the client) */ @@ -3679,7 +3730,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * || skill_id == HW_GRAVITATION #endif || skill_id == NPC_EVILLAND) && !shadow_flag ) - status_fix_damage(src,bl,damage,dmg.dmotion); //Deal damage before knockback to allow stuff like firewall+storm gust combo. + status_fix_damage(src,bl,damage,dmg.dmotion,skill_id); //Deal damage before knockback to allow stuff like firewall+storm gust combo. if( !status_isdead(bl) && additional_effects ) skill_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,dmg.dmg_lv,tick); if( damage > 0 ) //Counter status effects [Skotlex] @@ -3701,7 +3752,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * battle_delay_damage(tick, dmg.amotion,src,bl,dmg.flag,skill_id,skill_lv,damage,dmg.dmg_lv,dmg.dmotion, additional_effects, false); } - if (tsc && skill_id != NPC_EVILLAND + if (tsc && skill_id != NPC_EVILLAND && skill_id != SP_SOULEXPLOSION && skill_id != SJ_NOVAEXPLOSING #ifndef RENEWAL && skill_id != PA_PRESSURE && skill_id != HW_GRAVITATION #endif @@ -3717,7 +3768,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * { if (!rmdamage) { clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, DMG_NORMAL, 0, false); - status_fix_damage(NULL, d_bl, damage, 0); + status_fix_damage(NULL, d_bl, damage, 0, 0); } else { bool isDevotRdamage = false; @@ -3727,12 +3778,12 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * // This check is only for magical skill. // For BF_WEAPON skills types track var rdamage and function battle_calc_return_damage clif_damage(bl, (!isDevotRdamage) ? bl : d_bl, gettick(), 0, 0, damage, 0, DMG_NORMAL, 0, false); - status_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, damage, 0); + status_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, damage, 0, 0); } } else { status_change_end(bl, SC_DEVOTION, INVALID_TIMER); if (!dmg.amotion) - status_fix_damage(src, bl, damage, dmg.dmotion); + status_fix_damage(src, bl, damage, dmg.dmotion, 0); } } if (tsc->data[SC_WATER_SCREEN_OPTION]) { @@ -3742,10 +3793,10 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * if (e_bl) { if (!rmdamage) { clif_skill_damage(e_bl, e_bl, gettick(), 0, 0, damage, dmg.div_, skill_id, -1, skill_get_hit(skill_id)); - status_fix_damage(NULL, e_bl, damage, 0); + status_fix_damage(NULL, e_bl, damage, 0, 0); } else { clif_skill_damage(bl, bl, gettick(), 0, 0, damage, dmg.div_, skill_id, -1, skill_get_hit(skill_id)); - status_fix_damage(bl, bl, damage, 0); + status_fix_damage(bl, bl, damage, 0, 0); } } } @@ -4609,7 +4660,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui } case 4: // THE CHARIOT - 1000 damage, random armor destroyed { - status_fix_damage(src, target, 1000, 0); + status_fix_damage(src, target, 1000, 0, skill_id); clif_damage(src, target, tick, 0, 0, 1000, 0, DMG_NORMAL, 0, false); if (!status_isdead(target)) { @@ -4659,7 +4710,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui } case 11: // THE DEVIL - 6666 damage, atk and matk halved, cursed { - status_fix_damage(src, target, 6666, 0); + status_fix_damage(src, target, 6666, 0, skill_id); clif_damage(src, target, tick, 0, 0, 6666, 0, DMG_NORMAL, 0, false); sc_start(src, target, SC_INCATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv)); sc_start(src, target, SC_INCMATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv)); @@ -4668,7 +4719,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui } case 12: // THE TOWER - 4444 damage { - status_fix_damage(src, target, 4444, 0); + status_fix_damage(src, target, 4444, 0, skill_id); clif_damage(src, target, tick, 0, 0, 4444, 0, DMG_NORMAL, 0, false); break; } @@ -5155,6 +5206,15 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SU_SCRATCH: case SU_LUNATICCARROTBEAT: case SU_LUNATICCARROTBEAT2: + case SJ_FULLMOONKICK: + case SJ_NEWMOONKICK: + case SJ_SOLARBURST: + case SJ_PROMINENCEKICK: + case SJ_STAREMPEROR: + case SJ_FALLINGSTAR_ATK2: + case SP_CURSEEXPLOSION: + case SP_SHA: + case SP_SWHOO: if( flag&1 ) {//Recursive invocation int sflag = skill_area_temp[0] & 0xFFF; int heal = 0; @@ -5168,11 +5228,18 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if( skill_area_temp[1] != bl->id && !inf2[INF2_ISNPC] ) sflag |= SD_ANIMATION; // original target gets no animation (as well as all NPC skills) + // If a enemy player is standing next to a mob when splash Es- skill is casted, the player won't get hurt. + if ((skill_id == SP_SHA || skill_id == SP_SWHOO) && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) + 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); status_heal(src,heal,0,0); } + + if (skill_id == SJ_PROMINENCEKICK) // Trigger the 2nd hit. (100% fire damage.) + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag|8|SD_ANIMATION); } else { int starget = BL_CHAR|BL_SKILL; @@ -5180,6 +5247,15 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill_area_temp[1] = bl->id; skill_area_temp[2] = 0; + if (sd && (skill_id == SP_SHA || skill_id == SP_SWHOO) && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { + status_change_start(src, bl, SC_STUN, 10000, skill_lv, 0, 0, 0, 500, 10); + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + + if (skill_id == SP_SWHOO) + status_change_end(src, SC_USE_SKILL_SP_SPA, INVALID_TIMER); + switch ( skill_id ) { case LG_EARTHDRIVE: case GN_CARTCANNON: @@ -5452,10 +5528,33 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill_attack(BF_MAGIC, src, src, bl, skill_id, skill_lv, tick, flag); break; + case SJ_NOVAEXPLOSING: + skill_attack(BF_MISC, src, src, bl, skill_id, skill_lv, tick, flag); + + // We can end Dimension here since the cooldown code is processed before this point. + if (sc && sc->data[SC_DIMENSION]) + status_change_end(src, SC_DIMENSION, INVALID_TIMER); + else // Dimension not active? Activate the 2 second skill block penalty. + sc_start(src, &sd->bl, SC_NOVAEXPLOSING, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + break; + + case SP_SOULEXPLOSION: + if (!(tsc && (tsc->data[SC_SPIRIT] || tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY])) || tstatus->hp < 10 * tstatus->max_hp / 100) { // Requires target to have a soul link and more then 10% of MaxHP. + // With this skill requiring a soul link, and the target to have more then 10% if MaxHP, I wonder + // if the cooldown still happens after it fails. Need a confirm. [Rytech] + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + + skill_attack(BF_MISC, src, src, bl, skill_id, skill_lv, tick, flag); + break; + case SL_SMA: status_change_end(src, SC_SMA, INVALID_TIMER); case SL_STIN: case SL_STUN: + case SP_SPA: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,SCSTART_NOTICKDEF|SCSTART_NORATEDEF); clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -5894,6 +5993,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); if (tsc && tsc->data[SC__SHADOWFORM] && rnd() % 100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); sc_start(src,bl, SC_INFRAREDSCAN, 10000, skill_lv, skill_get_time(skill_id, skill_lv)); @@ -6195,6 +6295,80 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } break; + case SJ_FALLINGSTAR_ATK: + if (sd) { // If a player used the skill it will search for targets marked by that player. + if (tsc && tsc->data[SC_FLASHKICK] && tsc->data[SC_FLASHKICK]->val4 == 1) { // Mark placed by a player. + int8 i = 0; + + ARR_FIND(0, MAX_STELLAR_MARKS, i, sd->stellar_mark[i] == bl->id); + if (i < MAX_STELLAR_MARKS) { + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + skill_castend_damage_id(src, bl, SJ_FALLINGSTAR_ATK2, skill_lv, tick, 0); + } + } + } else if ( tsc && tsc->data[SC_FLASHKICK] && tsc->data[SC_FLASHKICK]->val4 == 2 ) { // Mark placed by a monster. + // If a monster used the skill it will search for targets marked by any monster since they can't track their own targets. + skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + skill_castend_damage_id(src, bl, SJ_FALLINGSTAR_ATK2, skill_lv, tick, 0); + } + break; + case SJ_FLASHKICK: { + struct map_session_data *tsd = BL_CAST(BL_PC, bl); + struct mob_data *md = BL_CAST(BL_MOB, src), *tmd = BL_CAST(BL_MOB, bl); + + // Only players and monsters can be tagged....I think??? [Rytech] + // Lets only allow players and monsters to use this skill for safety reasons. + if ((!tsd && !tmd) || !sd && !md) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + + // Check if the target is already tagged by another source. + if ((tsd && tsd->sc.data[SC_FLASHKICK] && tsd->sc.data[SC_FLASHKICK]->val1 != src->id) || (tmd && tmd->sc.data[SC_FLASHKICK] && tmd->sc.data[SC_FLASHKICK]->val1 != src->id)) { // Same as the above check, but for monsters. + // Can't tag a player that was already tagged from another source. + if (sd) + clif_skill_fail(sd,skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + + // Attack the target and return the damage result for the upcoming check. + int64 fk_damage = skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + + if (sd) { // Tagging the target. + int i; + + ARR_FIND(0, MAX_STELLAR_MARKS, i, sd->stellar_mark[i] == bl->id); + if (i == MAX_STELLAR_MARKS) { + ARR_FIND(0, MAX_STELLAR_MARKS, i, sd->stellar_mark[i] == 0); + if (i == MAX_STELLAR_MARKS) { // Max number of targets tagged. Fail the skill. + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + } + + // Tag the target only if damage was done. If it deals no damage, it counts as a miss and won't tag. + // Note: Not sure if it works like this in official but you can't mark on something you can't + // hit, right? For now well just use this logic until we can get a confirm on if it does this or not. [Rytech] + if (fk_damage > 0) { // Add the ID of the tagged target to the player's tag list and start the status on the target. + sd->stellar_mark[i] = bl->id; + + // Val4 flags if the status was applied by a player or a monster. + // This will be important for other skills that work together with this one. + // 1 = Player, 2 = Monster. + // Note: Because the attacker's ID and the slot number is handled here, we have to + // apply the status here. We can't pass this data to skill_additional_effect. + sc_start4(src, bl, SC_FLASHKICK, 100, src->id, i, skill_lv, 1, skill_get_time(skill_id, skill_lv)); + } + } else if (md) { // Monster's cant track with this skill. Just give the status. + if (fk_damage > 0) + sc_start4(src, bl, SC_FLASHKICK, 100, 0, 0, skill_lv, 2, skill_get_time(skill_id, skill_lv)); + } + } + break; + default: ShowWarning("skill_castend_damage_id: Unknown skill used:%d\n",skill_id); clif_skill_damage(src, bl, tick, status_get_amotion(src), tstatus->dmotion, @@ -6562,6 +6736,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case SP_SOULCURSE: + if (flag&1) + sc_start(src, bl, type, 30 + 10 * skill_lv, skill_lv, skill_get_time(skill_id, skill_lv)); + else { + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + break; + case PR_LEXDIVINA: case MER_LEXDIVINA: if (tsce) @@ -6958,10 +7141,29 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SU_FRESHSHRIMP: case SU_ARCLOUSEDASH: case NPC_MAXPAIN: + case SP_SOULREAPER: + case SJ_LIGHTOFMOON: + case SJ_LIGHTOFSTAR: + case SJ_FALLINGSTAR: + case SJ_LIGHTOFSUN: + case SJ_BOOKOFDIMENSION: 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; + case SJ_GRAVITYCONTROL: { + int fall_damage = sstatus->batk + sstatus->rhw.atk - tstatus->def2; + + if (bl->type == BL_PC) + fall_damage += dstsd->weight / 10 - tstatus->def; + else // Monster's don't have weight. Put something in its place. + fall_damage += 50 * status_get_lv(src) - tstatus->def; + + fall_damage = max(1, fall_damage); + + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, fall_damage, skill_get_time(skill_id, skill_lv))); + } + break; case NPC_HALLUCINATION: case NPC_HELLPOWER: clif_skill_nodamage(src, bl, skill_id, skill_lv, @@ -7198,6 +7400,45 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case SP_SOULUNITY: { + int8 count = min(5 + skill_lv, MAX_UNITED_SOULS); + + if (sd == nullptr || sd->status.party_id == 0 || (flag & 1)) { + if (!dstsd || !sd) { // Only put player's souls in unity. + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + + if (dstsd->sc.data[type] && dstsd->sc.data[type]->val2 != src->id) { // Fail if a player is in unity with another source. + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + + if (sd) { // Unite player's soul with caster's soul. + i = 0; + + ARR_FIND(0, count, i, sd->united_soul[i] == bl->id); + if (i == count) { + ARR_FIND(0, count, i, sd->united_soul[i] == 0); + if(i == count) { // No more free slots? Fail the skill. + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + map_freeblock_unlock(); + return 1; + } + } + + sd->united_soul[i] = bl->id; + } + + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start4(src, bl, type, 100, skill_lv, src->id, i, 0, skill_get_time(skill_id, skill_lv))); + } else if (sd) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + } + break; + case MO_CALLSPIRITS: if(sd) { int limit = skill_lv; @@ -7314,12 +7555,37 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KO_HAPPOKUNAI: case RL_FIREDANCE: case RL_R_TRIP: + case SJ_FULLMOONKICK: + case SJ_NEWMOONKICK: + case SJ_SOLARBURST: + case SJ_STAREMPEROR: + case SJ_FALLINGSTAR_ATK: { struct status_change *sc = status_get_sc(src); int starget = BL_CHAR|BL_SKILL; if (skill_id == SR_HOWLINGOFLION) starget = splash_target(src); + if (skill_id == SJ_NEWMOONKICK) { + if (tsce) { + status_change_end(bl, type, INVALID_TIMER); + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + } else + sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + } + if (skill_id == SJ_STAREMPEROR && sc && sc->data[SC_DIMENSION]) { + if (sd) { + // Remove old shields if any exist. + pc_delspiritball(sd, sd->spiritball, 0); + for (i = 0; i < 2; i++) { + pc_addspiritball(sd, skill_get_time2(SJ_BOOKOFDIMENSION, 1), 2); + sc_start2(src, bl, static_cast(SC_DIMENSION1 + i), 100, skill_lv, status_get_max_sp(src), skill_get_time2(SJ_BOOKOFDIMENSION, 1)); + } + } + status_change_end(src, SC_DIMENSION, INVALID_TIMER); + } + skill_area_temp[1] = 0; clif_skill_nodamage(src,bl,skill_id,skill_lv,1); i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, @@ -7413,7 +7679,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui map_freeblock_unlock(); return 1; } - status_damage(src, src, sstatus->max_hp,0,0,1); + status_damage(src, src, sstatus->max_hp,0,0,1, skill_id); break; case AL_ANGELUS: @@ -7476,6 +7742,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case CR_SHRINK: case SG_FUSION: case GS_GATLINGFEVER: + case SJ_LUNARSTANCE: + case SJ_STARSTANCE: + case SJ_UNIVERSESTANCE: + case SJ_SUNSTANCE: if( tsce ) { clif_skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); @@ -7484,25 +7754,43 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } 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; + case SP_SOULCOLLECT: + if (tsce) { + clif_skill_nodamage(src, bl, skill_id, skill_lv, status_change_end(bl, type, INVALID_TIMER)); + map_freeblock_unlock(); + return 0; + } + clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start2(src, bl, type, 100, skill_lv, pc_checkskill(sd,SP_SOULENERGY), max(1000, skill_get_time(skill_id, skill_lv)))); + break; case SL_KAITE: case SL_KAAHI: case SL_KAIZEL: case SL_KAUPE: + case SP_KAUTE: if (sd) { if (!dstsd || !( (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SOULLINKER) || (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER || dstsd->status.char_id == sd->status.char_id || dstsd->status.char_id == sd->status.partner_id || - dstsd->status.char_id == sd->status.child + dstsd->status.char_id == sd->status.child || + (skill_id == SP_KAUTE && dstsd->sc.data[SC_SOULUNITY]) )) { status_change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,SCSTART_NORATEDEF); clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } } - clif_skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id, skill_lv))); + if (skill_id == SP_KAUTE) { + if (!status_charge(src, sstatus->max_hp * (10 + 2 * skill_lv) / 100, 0)) { + if (sd) + clif_skill_fail(sd,skill_id, USESKILL_FAIL,0); + break; + } + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_heal(bl, 0, tstatus->max_sp * (10 + 2 * skill_lv) / 100, 2); + } else + 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; case SM_AUTOBERSERK: case MER_AUTOBERSERK: @@ -7771,7 +8059,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( mer && mer->master ) { status_heal(&mer->master->bl, mer->battle_status.hp, 0, 2); - status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1); + status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1, skill_id); } break; @@ -8201,6 +8489,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_DECORATION_OF_MUSIC: case SC_GN_CARTBOOST: case SC_CHASEWALK2: case SC_ACTIVE_MONSTER_TRANSFORM: case SC_DORAM_BUF_01: case SC_DORAM_BUF_02: case SC_SPORE_EXPLOSION: + case SC_NEWMOON: case SC_FLASHKICK: case SC_NOVAEXPLOSING: + case SC_SOULUNITY: case SC_SOULSHADOW: case SC_SOULFAIRY: + case SC_SOULFALCON: case SC_SOULGOLEM: case SC_USE_SKILL_SP_SPA: + case SC_USE_SKILL_SP_SHA: case SC_SP_SHA: #ifdef RENEWAL case SC_EXTREMITYFIST2: #endif @@ -8994,6 +9286,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SL_STAR: case SL_SUPERNOVICE: case SL_WIZARD: + if (sd && tsc && (tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY])) { // Soul links from Soul Linker and Soul Reaper skills don't stack. + clif_skill_fail(sd, skill_id, USESKILL_FAIL,0); + break; + } //NOTE: here, 'type' has the value of the associated MAPID, not of the SC_SPIRIT constant. if (sd && dstsd && !((dstsd->class_&MAPID_UPPERMASK) == type)) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -9011,6 +9307,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sc_start(src,src,SC_SMA,100,skill_lv,skill_get_time(SL_SMA,skill_lv)); break; case SL_HIGH: + if (sd && tsc && (tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY])) { // Soul links from Soul Linker and Soul Reaper skills don't stack. + clif_skill_fail(sd, skill_id, USESKILL_FAIL,0); + break; + } if (sd && !(dstsd && (dstsd->class_&JOBL_UPPER) && !(dstsd->class_&JOBL_2) && dstsd->status.base_level < 70)) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; @@ -9019,6 +9319,39 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sc_start4(src,bl,type,100,skill_lv,skill_id,0,0,skill_get_time(skill_id,skill_lv))); sc_start(src,src,SC_SMA,100,skill_lv,skill_get_time(SL_SMA,skill_lv)); break; + case SP_SOULGOLEM: + case SP_SOULSHADOW: + case SP_SOULFALCON: + case SP_SOULFAIRY: + if (sd && !dstsd) { // Only player's can be soul linked. + clif_skill_fail(sd, skill_id, USESKILL_FAIL,0); + break; + } + if (tsc) { + if (tsc->data[status_skill2sc(skill_id)]) { // Allow refreshing an already active soul link. + 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; + } else if (tsc->data[SC_SPIRIT] || tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY]) { // Soul links from Soul Linker and Soul Reaper skills don't stack. + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + } + 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; + + case SP_SOULREVOLVE: + if (!(tsc && (tsc->data[SC_SPIRIT] || tsc->data[SC_SOULGOLEM] || tsc->data[SC_SOULSHADOW] || tsc->data[SC_SOULFALCON] || tsc->data[SC_SOULFAIRY]))) { + if (sd) + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + break; + } + status_heal(bl, 0, 50*skill_lv, 2); + status_change_end(bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(bl, SC_SOULGOLEM, INVALID_TIMER); + status_change_end(bl, SC_SOULSHADOW, INVALID_TIMER); + status_change_end(bl, SC_SOULFALCON, INVALID_TIMER); + status_change_end(bl, SC_SOULFAIRY, INVALID_TIMER); + break; case SL_SWOO: if (tsce) { @@ -9119,6 +9452,24 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; + case SJ_DOCUMENT: + if (sd) { + switch (skill_lv) { + case 1: + pc_resetfeel(sd); + break; + case 2: + pc_resethate(sd); + break; + case 3: + pc_resetfeel(sd); + pc_resethate(sd); + break; + } + } + clif_skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + case GS_GLITTERING: if(sd) { clif_skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -9596,7 +9947,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 60 + 8 * skill_lv) { + if(rnd()%100 >= 60 + 8 * skill_lv) { if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; @@ -9662,6 +10013,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_MTF_MLEATKED: case SC_MTF_CRIDAMAGE: case SC_HEAT_BARREL: case SC_P_ALTER: case SC_E_CHAIN: case SC_C_MARKER: case SC_B_TRAP: case SC_H_MINE: + case SC_NEWMOON: case SC_FLASHKICK: case SC_DIMENSION: + case SC_NOVAEXPLOSING: + case SC_SOULUNITY: case SC_SOULSHADOW: case SC_SOULFAIRY: + case SC_SOULFALCON: case SC_SOULGOLEM: case SC_USE_SKILL_SP_SPA: + case SC_USE_SKILL_SP_SHA: case SC_SP_SHA: case SC_STRANGELIGHTS: case SC_DECORATION_OF_MUSIC: case SC_GN_CARTBOOST: case SC_RECOGNIZEDSPELL: case SC_CHASEWALK2: case SC_ACTIVE_MONSTER_TRANSFORM: case SC_SPORE_EXPLOSION: @@ -10003,6 +10359,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl,SC_CLOAKING,INVALID_TIMER); status_change_end(bl,SC_CLOAKINGEXCEED,INVALID_TIMER); status_change_end(bl,SC_CAMOUFLAGE,INVALID_TIMER); + status_change_end(bl,SC_NEWMOON,INVALID_TIMER); if (tsc && tsc->data[SC__SHADOWFORM] && rnd() % 100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); } @@ -10394,7 +10751,7 @@ 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)); } else if( flag&2 ) { if( src->id != bl->id && battle_check_target(src,bl,BCT_ENEMY) > 0 ) - status_fix_damage(src,bl,9999,clif_damage(src,bl,tick,0,0,9999,0,DMG_NORMAL,0,false)); + status_fix_damage(src,bl,9999,clif_damage(src,bl,tick,0,0,9999,0,DMG_NORMAL,0,false),skill_id); } else if( sd ) { short chance = sstatus->int_/6 + sd->status.job_level/5 + skill_lv*4; if( !sd->status.party_id || (rnd()%100 > chance)) { @@ -10410,7 +10767,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif_skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src,src,SC_STOP,100,skill_lv,skill_get_time2(skill_id,skill_lv))); if( flag&2 ) // Dealed here to prevent conflicts - status_fix_damage(src,bl,9999,clif_damage(src,bl,tick,0,0,9999,0,DMG_NORMAL,0,false)); + status_fix_damage(src,bl,9999,clif_damage(src,bl,tick,0,0,9999,0,DMG_NORMAL,0,false),skill_id); } break; case WM_SONG_OF_MANA: @@ -10956,6 +11313,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case OB_ZANGETSU: case KG_KYOMU: case KG_KAGEMUSYA: + case SP_SOULDIVISION: + if (skill_id == SP_SOULDIVISION) { // Usable only on other players. + if (bl->type != BL_PC) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + } + clif_skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, DMG_SINGLE); @@ -10971,6 +11336,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); if (tsc && tsc->data[SC__SHADOWFORM] && rnd() % 100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); status_change_end(bl, SC_MARIONETTE, INVALID_TIMER); @@ -12161,6 +12527,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case MH_STEINWAND: case MH_XENO_SLASHER: case LG_KINGS_GRACE: + case SJ_BOOKOFCREATINGSTAR: case RL_B_TRAP: flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. @@ -12577,7 +12944,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } map_foreachinallrange(unit_changetarget, src, AREA_SIZE, BL_MOB, src, &group->unit->bl); // Release all targets against the caster skill_blown(src, src, skill_get_blewcount(skill_id, skill_lv), unit_getdir(src), BLOWN_IGNORE_NO_KNOCKBACK); // Don't stop the caster from backsliding if special_state.no_knockback is active - clif_skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); + clif_skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,skill_get_time2(skill_id,skill_lv))); } break; @@ -13914,6 +14281,11 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, t_ sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id, sg->skill_lv)); break; + case UNT_CREATINGSTAR: + if (!sce) + sc_start4(ss, bl, type, 100, sg->skill_lv, ss->id, unit->bl.id, 0, sg->limit); + break; + case UNT_GD_LEADERSHIP: case UNT_GD_GLORYWOUNDS: case UNT_GD_SOULCOLD: @@ -14446,6 +14818,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t status_change_end(bl,SC_CLOAKING,INVALID_TIMER); status_change_end(bl,SC_CLOAKINGEXCEED,INVALID_TIMER); status_change_end(bl,SC_CAMOUFLAGE,INVALID_TIMER); + status_change_end(bl,SC_NEWMOON,INVALID_TIMER); if (tsc && tsc->data[SC__SHADOWFORM] && rnd() % 100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); } @@ -14789,6 +15162,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, t_tick tick) case SO_WATER_INSIGNIA: case SO_WIND_INSIGNIA: case SO_EARTH_INSIGNIA: + case SJ_BOOKOFCREATINGSTAR: case SC_BLOODYLUST: case GN_FIRE_EXPANSION_SMOKE_POWDER: case GN_FIRE_EXPANSION_TEAR_GAS: @@ -15243,6 +15617,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i { //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] sd->state.arrow_atk = skill_get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. + sd->soulball_old = sd->soulball; //Need to do Soulball check. return true; } @@ -15431,6 +15806,10 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i if(sc->data[SC_COMBO]->val1 != MO_COMBOFINISH && sc->data[SC_COMBO]->val1 != CH_TIGERFIST) return false; break; + case SJ_SOLARBURST: + if (!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SJ_PROMINENCEKICK)) + return 0; + break; case MO_EXTREMITYFIST: // if(sc && sc->data[SC_EXTREMITYFIST]) //To disable Asura during the 5 min skill block uncomment this... // return false; @@ -15528,7 +15907,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i } break; case SL_SMA: - if(!(sc && sc->data[SC_SMA])) + if(sc && !(sc->data[SC_SMA] || sc->data[SC_USE_SKILL_SP_SHA])) return false; break; case HT_POWER: @@ -15686,6 +16065,12 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i if (status->sp == status->max_sp) return false; //Unusable when at full SP. break; + case SP_KAUTE: // Fail if below 30% MaxHP. + if (status->hp < 30 * status->max_hp / 100) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return false; + } + break; case AM_CALLHOMUN: //Can't summon if a hom is already out if (sd->status.hom_id && sd->hd && !sd->hd->homunculus.vaporize) { clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -15944,6 +16329,28 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i return false; } break; + case SJ_FULLMOONKICK: + if (!(sc && sc->data[SC_NEWMOON])) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + break; + case SJ_STAREMPEROR: + case SJ_NOVAEXPLOSING: + case SJ_GRAVITYCONTROL: + case SJ_BOOKOFDIMENSION: + case SJ_BOOKOFCREATINGSTAR: + case SP_SOULDIVISION: + case SP_SOULEXPLOSION: + if (!map_flag_vs(sd->bl.m)) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return false; + } + break; + case SP_SWHOO: + if (!(sc && sc->data[SC_USE_SKILL_SP_SPA])) + return false; + break; } /* check state required */ @@ -16041,6 +16448,30 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i return false; } break; + case ST_SUNSTANCE: + if (!(sc && (sc->data[SC_SUNSTANCE] || sc->data[SC_UNIVERSESTANCE]))) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return false; + } + break; + case ST_MOONSTANCE: + if (!(sc && (sc->data[SC_LUNARSTANCE] || sc->data[SC_UNIVERSESTANCE]))) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return false; + } + break; + case ST_STARSTANCE: + if (!(sc && (sc->data[SC_STARSTANCE] || sc->data[SC_UNIVERSESTANCE]))) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return false; + } + break; + case ST_UNIVERSESTANCE: + if (!(sc && sc->data[SC_UNIVERSESTANCE])) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0); + return false; + } + break; } /* check the status required */ @@ -16153,13 +16584,37 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i return false; } - if ((require.spiritball > 0 && sd->spiritball < require.spiritball) || - (require.spiritball == -1 && sd->spiritball < 1)) { - if ((sd->class_&MAPID_BASEMASK) == MAPID_GUNSLINGER || (sd->class_&MAPID_UPPERMASK) == MAPID_REBELLION) - clif_skill_fail(sd, skill_id, USESKILL_FAIL_COINS, (require.spiritball == -1) ? 1 : require.spiritball); - else - clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPIRITS, (require.spiritball == -1) ? 1 : require.spiritball); - return false; + if (require.spiritball > 0) { // Skills that require certain types of spheres to use. + switch (skill_id) { // Skills that require soul spheres. + case SP_SOULGOLEM: + case SP_SOULSHADOW: + case SP_SOULFALCON: + case SP_SOULFAIRY: + case SP_SOULCURSE: + case SP_SPA: + case SP_SHA: + case SP_SWHOO: + case SP_SOULUNITY: + case SP_SOULDIVISION: + case SP_SOULREAPER: + case SP_SOULEXPLOSION: + case SP_KAUTE: + if (sd->soulball < require.spiritball) { + clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPIRITS, 0); + return false; + } + break; + + default: // Skills that require spirit/coin spheres. + if (sd->spiritball < require.spiritball) { + if ((sd->class_&MAPID_BASEMASK) == MAPID_GUNSLINGER || (sd->class_&MAPID_UPPERMASK) == MAPID_REBELLION) + clif_skill_fail(sd, skill_id, USESKILL_FAIL_COINS, (require.spiritball == -1) ? 1 : require.spiritball); + else + clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPIRITS, (require.spiritball == -1) ? 1 : require.spiritball); + return false; + } + break; + } } return true; @@ -16189,6 +16644,7 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] sd->state.arrow_atk = skill_get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. + sd->soulball_old = sd->soulball; //Need to do Soulball check. return true; } @@ -16401,8 +16857,29 @@ void skill_consume_requirement(struct map_session_data *sd, uint16 skill_id, uin if(require.hp || require.sp) status_zap(&sd->bl, require.hp, require.sp); - if(require.spiritball > 0) - pc_delspiritball(sd,require.spiritball,0); + if(require.spiritball > 0) { // Skills that require certain types of spheres to use + switch (skill_id) { // Skills that require soul spheres. + case SP_SOULGOLEM: + case SP_SOULSHADOW: + case SP_SOULFALCON: + case SP_SOULFAIRY: + case SP_SOULCURSE: + case SP_SPA: + case SP_SHA: + case SP_SWHOO: + case SP_SOULUNITY: + case SP_SOULDIVISION: + case SP_SOULREAPER: + case SP_SOULEXPLOSION: + case SP_KAUTE: + pc_delsoulball(sd, require.spiritball, 0); + break; + + default: // Skills that require spirit/coin spheres. + pc_delspiritball(sd, require.spiritball, 0); + break; + } + } else if(require.spiritball == -1) { sd->spiritball_old = sd->spiritball; pc_delspiritball(sd,sd->spiritball,0); @@ -17016,6 +17493,8 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 VARCAST_REDUCTION(30); //Reduces 30% Variable Cast Time of magic Water spells. if (sc->data[SC_TELEKINESIS_INTENSE]) VARCAST_REDUCTION(sc->data[SC_TELEKINESIS_INTENSE]->val2); + if (sc->data[SC_SOULFAIRY]) + VARCAST_REDUCTION(sc->data[SC_SOULFAIRY]->val3); // Multiplicative Fixed CastTime values if (sc->data[SC_SECRAMENT]) fixcast_r = max(fixcast_r, sc->data[SC_SECRAMENT]->val2); @@ -17083,6 +17562,7 @@ int skill_delayfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv) case CH_CHAINCRUSH: case SR_DRAGONCOMBO: case SR_FALLENEMPIRE: + case SJ_PROMINENCEKICK: //If delay not specified, it will be 1000 - 4*agi - 2*dex if (time == 0) time = 1000; @@ -18197,7 +18677,7 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit) return false; } - status_damage(bl, src, damage, 0, clif_damage(src, src, gettick(), 500, 500, damage, hit, (hit > 1 ? DMG_MULTI_HIT : DMG_NORMAL), 0, false), 0); + status_damage(bl, src, damage, 0, clif_damage(src, src, gettick(), 500, 500, damage, hit, (hit > 1 ? DMG_MULTI_HIT : DMG_NORMAL), 0, false), 0, SC__SHADOWFORM); if( sc && sc->data[SC__SHADOWFORM] && (--sc->data[SC__SHADOWFORM]->val3) <= 0 ) { status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); if( src->type == BL_PC ) @@ -21239,6 +21719,11 @@ int skill_disable_check(struct status_change *sc, uint16 skill_id) case KO_YAMIKUMO: case RA_WUGDASH: case RA_CAMOUFLAGE: + case SJ_LUNARSTANCE: + case SJ_STARSTANCE: + case SJ_UNIVERSESTANCE: + case SJ_SUNSTANCE: + case SP_SOULCOLLECT: if( sc->data[status_skill2sc(skill_id)] ) return 1; break; diff --git a/src/map/skill.hpp b/src/map/skill.hpp index c51e4f45e9..380925ca99 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -646,6 +646,10 @@ enum e_require_state : uint8 { ST_ELEMENTALSPIRIT, ST_ELEMENTALSPIRIT2, ST_PECO, + ST_SUNSTANCE, + ST_MOONSTANCE, + ST_STARSTANCE, + ST_UNIVERSESTANCE }; /// List of Skills @@ -2227,6 +2231,8 @@ enum e_skill_unit_id : uint16 { UNT_CATNIPPOWDER, UNT_NYANGGRASS, + UNT_CREATINGSTAR, + /** * Guild Auras **/ diff --git a/src/map/status.cpp b/src/map/status.cpp index 09317fd749..fa6a6e3da6 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -1065,6 +1065,36 @@ void initChangeTables(void) set_sc( WE_CHEERUP , SC_CHEERUP , EFST_CHEERUP , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + // Star Emperor + set_sc( SJ_LIGHTOFMOON , SC_LIGHTOFMOON , EFST_LIGHTOFMOON , SCB_NONE ); + set_sc( SJ_LIGHTOFSTAR , SC_LIGHTOFSTAR , EFST_LIGHTOFSTAR , SCB_NONE ); + set_sc( SJ_LUNARSTANCE , SC_LUNARSTANCE , EFST_LUNARSTANCE , SCB_MAXHP ); + add_sc( SJ_FULLMOONKICK , SC_BLIND ); + set_sc( SJ_STARSTANCE , SC_STARSTANCE , EFST_STARSTANCE , SCB_ASPD ); + set_sc( SJ_NEWMOONKICK , SC_NEWMOON , EFST_NEWMOON , SCB_NONE ); + set_sc( SJ_FLASHKICK , SC_FLASHKICK , EFST_FLASHKICK , SCB_NONE ); + add_sc( SJ_STAREMPEROR , SC_SILENCE ); + set_sc( SJ_NOVAEXPLOSING , SC_NOVAEXPLOSING , EFST_NOVAEXPLOSING , SCB_NONE ); + set_sc( SJ_UNIVERSESTANCE , SC_UNIVERSESTANCE , EFST_UNIVERSESTANCE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + set_sc( SJ_FALLINGSTAR , SC_FALLINGSTAR , EFST_FALLINGSTAR , SCB_NONE ); + set_sc( SJ_GRAVITYCONTROL , SC_GRAVITYCONTROL , EFST_GRAVITYCONTROL , SCB_NONE ); + set_sc( SJ_BOOKOFDIMENSION , SC_DIMENSION , EFST_DIMENSION , SCB_NONE ); + set_sc( SJ_BOOKOFCREATINGSTAR , SC_CREATINGSTAR , EFST_CREATINGSTAR , SCB_SPEED ); + set_sc( SJ_LIGHTOFSUN , SC_LIGHTOFSUN , EFST_LIGHTOFSUN , SCB_NONE ); + set_sc( SJ_SUNSTANCE , SC_SUNSTANCE , EFST_SUNSTANCE , SCB_BATK|SCB_WATK ); + + // Soul Reaper + set_sc( SP_SOULGOLEM , SC_SOULGOLEM , EFST_SOULGOLEM , SCB_DEF|SCB_MDEF ); + set_sc( SP_SOULSHADOW , SC_SOULSHADOW , EFST_SOULSHADOW , SCB_ASPD|SCB_CRI ); + set_sc( SP_SOULFALCON , SC_SOULFALCON , EFST_SOULFALCON , SCB_WATK|SCB_HIT ); + set_sc( SP_SOULFAIRY , SC_SOULFAIRY , EFST_SOULFAIRY , SCB_MATK ); + set_sc( SP_SOULCURSE , SC_SOULCURSE , EFST_SOULCURSE , SCB_NONE ); + set_sc( SP_SHA , SC_SP_SHA , EFST_SP_SHA , SCB_SPEED ); + set_sc( SP_SOULUNITY , SC_SOULUNITY , EFST_SOULUNITY , SCB_NONE ); + set_sc( SP_SOULDIVISION , SC_SOULDIVISION , EFST_SOULDIVISION , SCB_NONE ); + set_sc( SP_SOULREAPER , SC_SOULREAPER , EFST_SOULREAPER , SCB_NONE ); + set_sc( SP_SOULCOLLECT , SC_SOULCOLLECT , EFST_SOULCOLLECT , SCB_NONE ); + /* Storing the target job rather than simply SC_SPIRIT simplifies code later on */ SkillStatusChangeTable[skill_get_index(SL_ALCHEMIST)] = (sc_type)MAPID_ALCHEMIST, SkillStatusChangeTable[skill_get_index(SL_MONK)] = (sc_type)MAPID_MONK, @@ -1511,6 +1541,10 @@ void initChangeTables(void) StatusChangeFlagTable[SC_DORAM_BUF_01] |= SCB_REGEN; StatusChangeFlagTable[SC_DORAM_BUF_02] |= SCB_REGEN; + // Soul Reaper + StatusIconChangeTable[SC_USE_SKILL_SP_SPA] = EFST_USE_SKILL_SP_SPA; + StatusIconChangeTable[SC_USE_SKILL_SP_SHA] = EFST_USE_SKILL_SP_SHA; + #ifdef RENEWAL // renewal EDP increases your weapon atk StatusChangeFlagTable[SC_EDP] |= SCB_WATK; @@ -1616,6 +1650,7 @@ void initChangeTables(void) #ifdef RENEWAL StatusChangeStateTable[SC_LONGING] |= SCS_NOMOVE; #endif + StatusChangeStateTable[SC_GRAVITYCONTROL] |= SCS_NOMOVE; /* StatusChangeState (SCS_) NOPICKUPITEMS */ StatusChangeStateTable[SC_HIDING] |= SCS_NOPICKITEM; @@ -1626,6 +1661,7 @@ void initChangeTables(void) StatusChangeStateTable[SC__FEINTBOMB] |= SCS_NOPICKITEM; StatusChangeStateTable[SC_NOCHAT] |= SCS_NOPICKITEM|SCS_NOPICKITEMCOND; StatusChangeStateTable[SC_SUHIDE] |= SCS_NOPICKITEM; + StatusChangeStateTable[SC_NEWMOON] |= SCS_NOPICKITEM; /* StatusChangeState (SCS_) NODROPITEMS */ StatusChangeStateTable[SC_AUTOCOUNTER] |= SCS_NODROPITEM; @@ -1653,6 +1689,7 @@ void initChangeTables(void) StatusChangeStateTable[SC_SATURDAYNIGHTFEVER] |= SCS_NOCAST; StatusChangeStateTable[SC_CURSEDCIRCLE_TARGET] |= SCS_NOCAST; StatusChangeStateTable[SC_KINGS_GRACE] |= SCS_NOCAST; + StatusChangeStateTable[SC_GRAVITYCONTROL] |= SCS_NOCAST; /* StatusChangeState (SCS_) NOCHAT (skills) */ StatusChangeStateTable[SC_BERSERK] |= SCS_NOCHAT; @@ -1818,7 +1855,7 @@ int64 status_charge(struct block_list* bl, int64 hp, int64 sp) { if(!(bl->type&BL_CONSUME)) return (int)hp+sp; // Assume all was charged so there are no 'not enough' fails. - return status_damage(NULL, bl, hp, sp, 0, 3); + return status_damage(NULL, bl, hp, sp, 0, 3, 0); } /** @@ -1837,7 +1874,7 @@ int64 status_charge(struct block_list* bl, int64 hp, int64 sp) * Note: HP/SP are integer values, not percentages. Values should be * calculated either within function call or before */ -int status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, t_tick walkdelay, int flag) +int status_damage(struct block_list *src,struct block_list *target,int64 dhp, int64 dsp, t_tick walkdelay, int flag, uint16 skill_id) { struct status_data *status; struct status_change *sc; @@ -1905,6 +1942,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER); status_change_end(target, SC_SUHIDE, INVALID_TIMER); + status_change_end(target, SC_NEWMOON, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { /** [Skotlex] * Endure count is only reduced by non-players on non-gvg maps. @@ -2094,7 +2132,7 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) if (hp < 0) { if (hp == INT_MIN) // -INT_MIN == INT_MIN in some architectures! hp++; - status_damage(NULL, bl, -hp, 0, 0, 1); + status_damage(NULL, bl, -hp, 0, 0, 1, 0); hp = 0; } @@ -2113,7 +2151,7 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) if(sp < 0) { if (sp == INT_MIN) sp++; - status_damage(NULL, bl, 0, -sp, 0, 1); + status_damage(NULL, bl, 0, -sp, 0, 1, 0); sp = 0; } @@ -2200,19 +2238,19 @@ int status_percent_change(struct block_list *src, struct block_list *target, int if (hp > INT_MAX) { hp -= INT_MAX; if (flag) - status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1)); + status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1), 0); else status_heal(target, INT_MAX, 0, 0); } if (sp > INT_MAX) { sp -= INT_MAX; if (flag) - status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1)); + status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1), 0); else status_heal(target, 0, INT_MAX, 0); } if (flag) - return status_damage(src, target, hp, sp, 0, (!src||src==target?5:1)); + return status_damage(src, target, hp, sp, 0, (!src||src==target?5:1), 0); return status_heal(target, hp, sp, 0); } @@ -2409,6 +2447,8 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui (sc->data[SC_ANKLE] && skill_block_check(src, SC_ANKLE, skill_id)) || (sc->data[SC_STASIS] && skill_block_check(src, SC_STASIS, skill_id)) || (sc->data[SC_BITE] && skill_block_check(src, SC_BITE, skill_id)) || + (sc->data[SC_NOVAEXPLOSING] && skill_block_check(src, SC_NOVAEXPLOSING, skill_id)) || + (sc->data[SC_GRAVITYCONTROL] && skill_block_check(src, SC_GRAVITYCONTROL, skill_id)) || (sc->data[SC_KAGEHUMI] && skill_block_check(src, SC_KAGEHUMI, skill_id)) )) return false; @@ -2476,7 +2516,7 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui if (tsc) { if ((tsc->option&hide_flag) && !is_boss && (tsd->special_state.perfect_hiding || !is_detect)) return false; - if (tsc->data[SC_CLOAKINGEXCEED] && !is_boss && (tsd->special_state.perfect_hiding || is_detect)) + if ((tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC_NEWMOON]) && !is_boss && (tsd->special_state.perfect_hiding || is_detect)) return false; // Works against insect and demon but not against bosses if (tsc->data[SC__FEINTBOMB] && (is_boss || is_detect)) return false; // Works against all @@ -2548,7 +2588,7 @@ int status_check_visibility(struct block_list *src, struct block_list *target) if (((tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_STEALTHFIELD] || tsc->data[SC_SUHIDE]) && !is_boss && (tsd->special_state.perfect_hiding || !is_detector)) return 0; - if (tsc->data[SC_CLOAKINGEXCEED] && !is_boss && ((tsd && tsd->special_state.perfect_hiding) || is_detector)) + if ((tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC_NEWMOON]) && !is_boss && ((tsd && tsd->special_state.perfect_hiding) || is_detector)) return 0; if (tsc->data[SC__FEINTBOMB] && !is_boss && !is_detector) return 0; @@ -2602,7 +2642,7 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat temp_aspd = (float)(sqrt(temp_aspd) * 0.25f) + 0xc4; if ((skill_lv = pc_checkskill(sd,SA_ADVANCEDBOOK)) > 0 && sd->status.weapon == W_BOOK) val += (skill_lv - 1) / 2 + 1; - if ((skill_lv = pc_checkskill(sd, SG_DEVIL)) > 0 && pc_is_maxjoblv(sd)) + if ((skill_lv = pc_checkskill(sd, SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd))) val += 1 + skill_lv; if ((skill_lv = pc_checkskill(sd,GS_SINGLEACTION)) > 0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) val += ((skill_lv + 1) / 2); @@ -3360,6 +3400,8 @@ static int status_get_hpbonus(struct block_list *bl, enum e_status_bonus type) { if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_HPRATE) bonus += 30; #endif + if(sc->data[SC_LUNARSTANCE]) + bonus += bonus * sc->data[SC_LUNARSTANCE]->val2 / 100; //Decreasing if(sc->data[SC_VENOMBLEED]) @@ -4353,7 +4395,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) #ifndef RENEWAL_ASPD if((skill=pc_checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK) base_status->aspd_rate -= 5*skill; - if((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && pc_is_maxjoblv(sd)) + if ((skill = pc_checkskill(sd,SG_DEVIL)) > 0 && ((sd->class_&MAPID_THIRDMASK) == MAPID_STAR_EMPEROR || pc_is_maxjoblv(sd))) base_status->aspd_rate -= 30*skill; if((skill=pc_checkskill(sd,GS_SINGLEACTION))>0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) @@ -5874,6 +5916,8 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT) str += 15; #endif + if (sc->data[SC_UNIVERSESTANCE]) + str += sc->data[SC_UNIVERSESTANCE]->val2; return (unsigned short)cap_value(str,0,USHRT_MAX); } @@ -5954,6 +5998,8 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT) agi += 15; #endif + if (sc->data[SC_UNIVERSESTANCE]) + agi += sc->data[SC_UNIVERSESTANCE]->val2; return (unsigned short)cap_value(agi,0,USHRT_MAX); } @@ -6024,6 +6070,8 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT) vit += 15; #endif + if (sc->data[SC_UNIVERSESTANCE]) + vit += sc->data[SC_UNIVERSESTANCE]->val2; return (unsigned short)cap_value(vit,0,USHRT_MAX); } @@ -6098,6 +6146,8 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang int_ += 3; if(sc->data[SC_GLASTHEIM_STATE]) int_ += sc->data[SC_GLASTHEIM_STATE]->val1; + if (sc->data[SC_UNIVERSESTANCE]) + int_ += sc->data[SC_UNIVERSESTANCE]->val2; if(bl->type != BL_PC) { if(sc->data[SC_STRIPHELM]) @@ -6191,6 +6241,8 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT) dex += 15; #endif + if (sc->data[SC_UNIVERSESTANCE]) + dex += sc->data[SC_UNIVERSESTANCE]->val2; return (unsigned short)cap_value(dex,0,USHRT_MAX); } @@ -6259,6 +6311,8 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ALLSTAT) luk += 15; #endif + if (sc->data[SC_UNIVERSESTANCE]) + luk += sc->data[SC_UNIVERSESTANCE]->val2; return (unsigned short)cap_value(luk,0,USHRT_MAX); } @@ -6336,6 +6390,8 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_ATKRATE) batk += batk * 20 / 100; #endif + if (sc->data[SC_SUNSTANCE]) + batk += batk * sc->data[SC_SUNSTANCE]->val2 / 100; return (unsigned short)cap_value(batk,0,USHRT_MAX); } @@ -6436,6 +6492,10 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk -= watk * sc->data[SC_CATNIPPOWDER]->val2 / 100; if (sc->data[SC_CHATTERING]) watk += sc->data[SC_CHATTERING]->val2; + if (sc->data[SC_SUNSTANCE]) + watk += watk * sc->data[SC_SUNSTANCE]->val2 / 100; + if (sc->data[SC_SOULFALCON]) + watk += sc->data[SC_SOULFALCON]->val2; return (unsigned short)cap_value(watk,0,USHRT_MAX); } @@ -6493,6 +6553,8 @@ static unsigned short status_calc_ematk(struct block_list *bl, struct status_cha matk += sc->data[SC_CHATTERING]->val2; if (sc->data[SC_DORAM_MATK]) matk += sc->data[SC_DORAM_MATK]->val1; + if (sc->data[SC_SOULFAIRY]) + matk += sc->data[SC_SOULFAIRY]->val2; return (unsigned short)cap_value(matk,0,USHRT_MAX); } @@ -6604,6 +6666,8 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch critical -= sc->data[SC__UNLUCKY]->val2; if(sc->data[SC_BEYONDOFWARCRY]) critical += sc->data[SC_BEYONDOFWARCRY]->val3; + if (sc->data[SC_SOULSHADOW]) + critical += 10 * sc->data[SC_SOULSHADOW]->val3; return (short)cap_value(critical,10,SHRT_MAX); } @@ -6668,6 +6732,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change if (sc->data[SC_NIBELUNGEN] && sc->data[SC_NIBELUNGEN]->val2 == RINGNBL_HIT) hit += 50; #endif + if (sc->data[SC_SOULFALCON]) + hit += sc->data[SC_SOULFALCON]->val3; return (short)cap_value(hit,1,SHRT_MAX); } @@ -6901,6 +6967,8 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, def -= def * sc->data[SC_OVERED_BOOST]->val4 / 100; if(sc->data[SC_GLASTHEIM_ITEMDEF]) def += sc->data[SC_GLASTHEIM_ITEMDEF]->val1; + if (sc->data[SC_SOULGOLEM]) + def += sc->data[SC_SOULGOLEM]->val2; return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -7027,6 +7095,8 @@ static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, mdef -= 20 * sc->data[SC_ODINS_POWER]->val1; if(sc->data[SC_GLASTHEIM_ITEMDEF]) mdef += sc->data[SC_GLASTHEIM_ITEMDEF]->val2; + if (sc->data[SC_SOULGOLEM]) + mdef += sc->data[SC_SOULGOLEM]->val3; return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -7186,6 +7256,10 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, sc->data[SC_B_TRAP]->val3 ); if (sc->data[SC_CATNIPPOWDER]) val = max(val, sc->data[SC_CATNIPPOWDER]->val3); + if (sc->data[SC_SP_SHA]) + val = max(val, sc->data[SC_SP_SHA]->val2); + if (sc->data[SC_CREATINGSTAR]) + val = max(val, 90); if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // Permanent item-based speedup val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate ); @@ -7428,6 +7502,8 @@ static short status_calc_fix_aspd(struct block_list *bl, struct status_change *s aspd -= sc->data[SC_MTF_ASPD]->val1; if (sc->data[SC_MTF_ASPD2]) aspd -= sc->data[SC_MTF_ASPD2]->val1; + if (sc->data[SC_SOULSHADOW]) + aspd -= 10 * sc->data[SC_SOULSHADOW]->val2; return cap_value(aspd, 0, 2000); // Will be recap for proper bl anyway } @@ -7578,6 +7654,8 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * aspd_rate -= sc->data[SC_GOLDENE_FERSE]->val3 * 10; if (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) aspd_rate -= 100; + if (sc->data[SC_STARSTANCE]) + aspd_rate -= 10 * sc->data[SC_STARSTANCE]->val2; return (short)cap_value(aspd_rate,0,SHRT_MAX); } @@ -8893,6 +8971,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if (status_change_isDisabledOnMap(type, map_getmapdata(bl->m))) return 0; + if (sc->data[SC_GRAVITYCONTROL]) + return 0; // !TODO: Confirm what statuses/conditions (if not all) are blocked. + // Uncomment to prevent status adding hp to gvg mob (like bloodylust=hp*3 etc... // if (bl->type == BL_MOB) // if (status_get_race2(bl) == RC2_GVG && status_sc2scb_flag(type)&SCB_MAXHP) return 0; @@ -8978,6 +9059,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_DECREASEAGI: case SC_QUAGMIRE: case SC_DONTFORGETME: + case SC_CREATINGSTAR: if(sc->data[SC_SPEEDUP1]) return 0; break; @@ -9123,6 +9205,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if( sd && pc_checkskill(sd, AS_CLOAKING) < 3 && !skill_check_cloaking(bl,NULL) ) return 0; break; + case SC_NEWMOON: + if (sc->data[SC_BITE]) + return 0; + break; case SC_MODECHANGE: { enum e_mode mode; @@ -9397,6 +9483,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_CATNIPPOWDER: case SC_SV_ROOTTWIST: case SC_BITESCAR: + case SC_SP_SHA: case SC_FRESHSHRIMP: return 0; } @@ -9515,6 +9602,30 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty // Cancels Normal Overthrust. [Skotlex] status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); break; + case SC_SUNSTANCE: + case SC_LUNARSTANCE: + case SC_STARSTANCE: + case SC_UNIVERSESTANCE: + if (sc->data[type]) + break; + status_change_end(bl, SC_SUNSTANCE, INVALID_TIMER); + status_change_end(bl, SC_LUNARSTANCE, INVALID_TIMER); + status_change_end(bl, SC_STARSTANCE, INVALID_TIMER); + status_change_end(bl, SC_UNIVERSESTANCE, INVALID_TIMER); + break; + case SC_SPIRIT: + case SC_SOULGOLEM: + case SC_SOULSHADOW: + case SC_SOULFALCON: + case SC_SOULFAIRY: + if (sc->data[type]) + break; + status_change_end(bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(bl, SC_SOULGOLEM, INVALID_TIMER); + status_change_end(bl, SC_SOULSHADOW, INVALID_TIMER); + status_change_end(bl, SC_SOULFALCON, INVALID_TIMER); + status_change_end(bl, SC_SOULFAIRY, INVALID_TIMER); + break; case SC_MAGNIFICAT: status_change_end(bl,SC_OFFERTORIUM,INVALID_TIMER); break; @@ -9893,6 +10004,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4: + case SC_FLASHKICK: + case SC_SOULUNITY: break; case SC_GOSPEL: // Must not override a casting gospel char. @@ -11762,6 +11875,83 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val2 = 30; // SP Recovery rate bonus break; + case SC_SUNSTANCE: + val2 = 2 + val1; // ATK Increase + tick = INFINITE_TICK; + break; + case SC_LUNARSTANCE: + val2 = 2 + val1; // MaxHP Increase + tick = INFINITE_TICK; + break; + case SC_STARSTANCE: + val2 = 4 + 2 * val1; // ASPD Increase + tick = INFINITE_TICK; + break; + case SC_UNIVERSESTANCE: + val2 = 2 + val1; // All Stats Increase + tick = INFINITE_TICK; + break; + case SC_NEWMOON: + val2 = 7; // Number of Regular Attacks Until Reveal + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_FALLINGSTAR: + val2 = 8 + 2 * (1 + val1) / 2; // Autocast Chance + if (val1 >= 7) + val2 += 1; // Make it 15% at level 7. + break; + case SC_CREATINGSTAR: + tick_time = 500; + val4 = tick / tick_time; + break; + case SC_LIGHTOFSUN: + case SC_LIGHTOFMOON: + case SC_LIGHTOFSTAR: + val2 = 5 * val1; // Skill Damage Increase. + break; + case SC_SOULGOLEM: + val2 = 60 * val1; // DEF Increase + val3 = 15 + 5 * val1; // MDEF Increase + break; + case SC_SOULSHADOW: + val2 = (1 + val1) / 2; // ASPD Increase + val3 = 10 + 2 * val1; // CRIT Increase + break; + case SC_SOULFALCON: + val2 = 10 * val1; // WATK Increase + val3 = 10; // HIT Increase + if (val1 >= 3) + val3 += 3; + else if (val1 >= 5) + val3 += 5; + break; + case SC_SOULFAIRY: + val2 = 10 * val1; // MATK Increase + val3 = 5; // Variable Cast Time Reduction + if (val1 >= 3) + val3 += 2; + else if (val1 >= 5) + val3 += 5; + break; + case SC_SOULUNITY: + tick_time = 3000; + val4 = tick / tick_time; + break; + case SC_SOULDIVISION: + val2 = 10 * val1; // Skill Aftercast Increase + break; + case SC_SOULREAPER: + val2 = 10 + 5 * val1; // Chance of Getting A Soul Sphere. + break; + case SC_SOULCOLLECT: + val2 = 5 + 3 * val2; // Max Soul Sphere's. + val3 = tick > 0 ? tick : 60000; + break; + case SC_SP_SHA: + val2 = 50; // Move speed reduction + break; + default: if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == -1 && StatusIconChangeTable[type] == EFST_BLANK ) { // Status change with no calc, no icon, and no skill associated...? @@ -11919,6 +12109,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty pc_setstand(sd, true); case SC_FREEZE: case SC_STUN: + case SC_GRAVITYCONTROL: if (sc->data[SC_DANCING]) unit_stop_walking(bl, 1); case SC_TRICKDEAD: @@ -11988,6 +12179,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_HANBOK: case SC_OKTOBERFEST: case SC_DRESSUP: + case SC_NEWMOON: case SC_SUHIDE: unit_stop_attack(bl); break; @@ -12122,6 +12314,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_CLOAKING: case SC_CLOAKINGEXCEED: case SC__INVISIBILITY: + case SC_NEWMOON: sc->option |= OPTION_CLOAK; case SC_CAMOUFLAGE: case SC_STEALTHFIELD: @@ -12683,7 +12876,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const int damage = status->max_hp*sce->val3/100; if(status->hp < damage) // to not kill him damage = status->hp-1; - status_damage(NULL,bl,damage,0,0,1); + status_damage(NULL,bl,damage,0,0,1,0); } break; case SC_PYROCLASTIC: @@ -12755,6 +12948,26 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; + case SC_FLASHKICK: { + map_session_data *tsd; + + if (!(tsd = map_id2sd(sce->val1))) + break; + + tsd->stellar_mark[sce->val2] = 0; + } + break; + + case SC_SOULUNITY: { + map_session_data *tsd; + + if (!(tsd = map_id2sd(sce->val2))) + break; + + tsd->united_soul[sce->val3] = 0; + } + break; + case SC_BLADESTOP: if(sce->val4) { int tid2 = sce->val4; //stop the status for the other guy of bladestop as well @@ -12961,7 +13174,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const struct block_list* src = map_id2bl(sce->val2); if( tid == -1 || !src) break; // Terminated by Damage - status_fix_damage(src,bl,400*sce->val1,clif_damage(bl,bl,gettick(),0,0,400*sce->val1,0,DMG_NORMAL,0,false)); + status_fix_damage(src,bl,400*sce->val1,clif_damage(bl,bl,gettick(),0,0,400*sce->val1,0,DMG_NORMAL,0,false),WL_WHITEIMPRISON); } break; case SC_WUGDASH: @@ -13051,6 +13264,32 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_INTRAVISION: calc_flag = SCB_ALL; // Required for overlapping break; + + case SC_SUNSTANCE: + status_change_end(bl, SC_LIGHTOFSUN, INVALID_TIMER); + break; + case SC_LUNARSTANCE: + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); + status_change_end(bl, SC_LIGHTOFMOON, INVALID_TIMER); + break; + case SC_STARSTANCE: + status_change_end(bl, SC_FALLINGSTAR, INVALID_TIMER); + status_change_end(bl, SC_LIGHTOFSTAR, INVALID_TIMER); + break; + case SC_UNIVERSESTANCE: + status_change_end(bl, SC_LIGHTOFSUN, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); + status_change_end(bl, SC_LIGHTOFMOON, INVALID_TIMER); + status_change_end(bl, SC_FALLINGSTAR, INVALID_TIMER); + status_change_end(bl, SC_LIGHTOFSTAR, INVALID_TIMER); + status_change_end(bl, SC_DIMENSION, INVALID_TIMER); + break; + case SC_GRAVITYCONTROL: + status_fix_damage(bl, bl, sce->val2, clif_damage(bl, bl, gettick(), 0, 0, sce->val2, 0, DMG_NORMAL, 0, false), 0); + clif_specialeffect(bl, 223, AREA); + clif_specialeffect(bl, 330, AREA); + break; + case SC_OVERED_BOOST: switch (bl->type) { case BL_HOM: { @@ -13158,6 +13397,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_CLOAKING: case SC_CLOAKINGEXCEED: case SC__INVISIBILITY: + case SC_NEWMOON: sc->option &= ~OPTION_CLOAK; case SC_CAMOUFLAGE: case SC_STEALTHFIELD: @@ -13518,7 +13758,7 @@ TIMER_FUNC(status_change_timer){ int64 damage = 1000 + (3 * status->max_hp) / 100; // Deals fixed (1000 + 3%*MaxHP) map_freeblock_lock(); dounlock = true; - status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0, false)); + status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0, false),0); } break; @@ -13526,7 +13766,7 @@ TIMER_FUNC(status_change_timer){ if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain. map_freeblock_lock(); dounlock = true; - status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0, false), 0); + status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0, false), 0, 0); } break; @@ -13579,7 +13819,7 @@ TIMER_FUNC(status_change_timer){ if (sce->val4 >= 0) { map_freeblock_lock(); dounlock = true; - status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0, false)); + status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0, false),0); } break; @@ -13588,7 +13828,7 @@ TIMER_FUNC(status_change_timer){ int64 damage = status->vit * (sce->val1 - 3) + (int)status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) map_freeblock_lock(); dounlock = true; - status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0, false)); + status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0, false),0); unit_skillcastcancel(bl, 2); } break; @@ -13908,7 +14148,7 @@ TIMER_FUNC(status_change_timer){ damage = 1; else damage = 200 + 100 * sce->val1 + status_get_int(src); - status_damage(src, bl, damage, 0, clif_damage(bl,bl,tick,status->amotion,status->dmotion+200,damage,1,DMG_NORMAL,0,false), 0); + status_damage(src, bl, damage, 0, clif_damage(bl,bl,tick,status->amotion,status->dmotion+200,damage,1,DMG_NORMAL,0,false), 0, 0); unit_skillcastcancel(bl,1); if ( sc->data[type] ) { sc_timer_next(1000 + tick); @@ -14024,7 +14264,7 @@ TIMER_FUNC(status_change_timer){ if (damage >= status->hp) damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum map_freeblock_lock(); - status_fix_damage(NULL, bl, damage, clif_damage(bl, bl, tick, 0, 0, damage, 0, DMG_NORMAL, 0, false)); + status_fix_damage(NULL, bl, damage, clif_damage(bl, bl, tick, 0, 0, damage, 0, DMG_NORMAL, 0, false),0); if (sc->data[type]) { sc_timer_next(1000 + tick); } @@ -14111,7 +14351,7 @@ TIMER_FUNC(status_change_timer){ map_freeblock_lock(); clif_damage(bl, bl, tick, 0, 0, damage, 1, DMG_MULTI_HIT_ENDURE, 0, false); - status_damage(src, bl, damage,0, 0, 1); + status_damage(src, bl, damage,0, 0, 1, 0); if( sc->data[type] ) { sc_timer_next(2000 + tick); } @@ -14305,6 +14545,46 @@ TIMER_FUNC(status_change_timer){ return 0; } break; + case SC_NEWMOON: + if (--(sce->val4) >= 0) { + if (!status_charge(bl, 0, 1)) + break; + sc_timer_next(1000 + tick); + return 0; + } + break; + case SC_CREATINGSTAR: + if (--(sce->val4) >= 0) { // Needed to check who the caster is and what AoE is giving the status. + struct block_list *star_caster = map_id2bl(sce->val2), *star_aoe = map_id2bl(sce->val3); + + if (!star_caster || status_isdead(star_caster) || star_caster->m != bl->m) + break; + + map_freeblock_lock(); + if (star_aoe) + skill_attack(BF_WEAPON,star_caster,star_aoe,bl,SJ_BOOKOFCREATINGSTAR,sce->val1,tick,0); + if (sc->data[type]) + sc_timer_next(500 + tick); + map_freeblock_unlock(); + return 0; + } + break; + case SC_SOULUNITY: + if (--(sce->val4) >= 0) { // Needed to check the caster's location for the range check. + struct block_list *unity_src = map_id2bl(sce->val2); + + if (!unity_src || status_isdead(unity_src) || unity_src->m != bl->m || !check_distance_bl(bl, unity_src, 11)) + break; + + status_heal(bl, 150 * sce->val1, 0, 2); + sc_timer_next(3000 + tick); + return 0; + } + break; + case SC_SOULCOLLECT: + pc_addsoulball(sd, skill_get_time2(SP_SOULCOLLECT, sce->val1), sce->val2); + sc_timer_next(sce->val3 + tick); + return 0; } // If status has an interval and there is at least 100ms remaining time, wait for next interval @@ -14349,17 +14629,19 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); if (tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 > 0 && sce->val4%2000 == 0) && // For every 2 seconds do the checking rnd()%100 < 100 - tsc->data[SC__SHADOWFORM]->val1 * 10) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); break; case SC_RUWACH: // Reveal hidden target and deal little dammages if enemy if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || - tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) { + tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_NEWMOON] || tsc->data[SC_CLOAKINGEXCEED])) { status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); if(battle_check_target( src, bl, BCT_ENEMY ) > 0) skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); } @@ -14610,6 +14892,7 @@ void status_change_clear_buffs(struct block_list* bl, uint8 type) case SC_FEAR: case SC_MAGNETICFIELD: case SC_NETHERWORLD: + case SC_CREATINGSTAR: if (!(type&SCCB_DEBUFFS)) continue; break; diff --git a/src/map/status.hpp b/src/map/status.hpp index 14849fb367..f83e1dc254 100644 --- a/src/map/status.hpp +++ b/src/map/status.hpp @@ -887,6 +887,39 @@ enum sc_type : int16 { SC_ENTRY_QUEUE_APPLY_DELAY, SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT, + // Star Emperor + SC_LIGHTOFMOON, + SC_LIGHTOFSUN, + SC_LIGHTOFSTAR, + SC_LUNARSTANCE, + SC_UNIVERSESTANCE, + SC_SUNSTANCE, + SC_FLASHKICK, + SC_NEWMOON, + SC_STARSTANCE, + SC_DIMENSION, + SC_DIMENSION1, + SC_DIMENSION2, + SC_CREATINGSTAR, + SC_FALLINGSTAR, + SC_NOVAEXPLOSING, + SC_GRAVITYCONTROL, + + // Soul Reaper + SC_SOULCOLLECT, + SC_SOULREAPER, + SC_SOULUNITY, + SC_SOULSHADOW, + SC_SOULFAIRY, + SC_SOULFALCON, + SC_SOULGOLEM, + SC_SOULDIVISION, + SC_SOULENERGY, + SC_USE_SKILL_SP_SPA, + SC_USE_SKILL_SP_SHA, + SC_SP_SHA, + SC_SOULCURSE, + #ifdef RENEWAL SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled #endif @@ -2432,13 +2465,13 @@ int status_sc2skill(sc_type sc); unsigned int status_sc2scb_flag(sc_type sc); int status_type2relevant_bl_types(int type); -int status_damage(struct block_list *src,struct block_list *target,int64 dhp,int64 dsp, t_tick walkdelay, int flag); +int status_damage(struct block_list *src,struct block_list *target,int64 dhp,int64 dsp, t_tick walkdelay, int flag, uint16 skill_id); //Define for standard HP damage attacks. -#define status_fix_damage(src, target, hp, walkdelay) status_damage(src, target, hp, 0, walkdelay, 0) +#define status_fix_damage(src, target, hp, walkdelay, skill) status_damage(src, target, hp, 0, walkdelay, 0, skill) //Define for standard SP damage attacks. -#define status_fix_spdamage(src, target, sp, walkdelay) status_damage(src, target, 0, sp, walkdelay, 0) +#define status_fix_spdamage(src, target, sp, walkdelay, skill) status_damage(src, target, 0, sp, walkdelay, 0, skill) //Define for standard HP/SP damage triggers. -#define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1) +#define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1, 0) //Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) int64 status_charge(struct block_list* bl, int64 hp, int64 sp); int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag); diff --git a/src/map/unit.cpp b/src/map/unit.cpp index df8f5b8b5e..f7979fd734 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -1924,6 +1924,10 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if (!src->prev) return 0; + } else if (sc->data[SC_NEWMOON] && skill_id != SJ_NEWMOONKICK) { + status_change_end(src, SC_NEWMOON, INVALID_TIMER); + if (!src->prev) + return 0; // Warped away! } } @@ -2097,6 +2101,11 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui } else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4)) { status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); + if (!src->prev) + return 0; + } else if (sc->data[SC_NEWMOON]) { + status_change_end(src, SC_NEWMOON, INVALID_TIMER); + if (!src->prev) return 0; } @@ -2904,6 +2913,8 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); status_change_end(bl, SC_TINDER_BREAKER, INVALID_TIMER); status_change_end(bl, SC_TINDER_BREAKER2, INVALID_TIMER); + status_change_end(bl, SC_FLASHKICK, INVALID_TIMER); + status_change_end(bl, SC_SOULUNITY, INVALID_TIMER); status_change_end(bl, SC_HIDING, INVALID_TIMER); // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later if ( bl->type != BL_PC ) { @@ -2924,6 +2935,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); status_change_end(bl, SC__MANHOLE, INVALID_TIMER); status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER); + status_change_end(bl, SC_NEWMOON, INVALID_TIMER); status_change_end(bl, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); // callme before warp status_change_end(bl, SC_SUHIDE, INVALID_TIMER); } @@ -3262,6 +3274,7 @@ int unit_free(struct block_list *bl, clr_type clrtype) pc_inventory_rental_clear(sd); pc_delspiritball(sd, sd->spiritball, 1); pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type); + pc_delsoulball(sd,sd->soulball, 1); if( sd->st && sd->st->state != RUN ) {// free attached scripts that are waiting script_free_state(sd->st);