Initial implementation of Night Watch (#8150)

Taken from #7024

Co-authored-by: munkrej <schmunk@posteo.de>
Co-authored-by: Atemo <Atemo@users.noreply.github.com>
This commit is contained in:
Lemongrass3110 2024-03-10 22:10:28 +01:00 committed by GitHub
parent 37d9196a4e
commit 4124cdaa4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1138 additions and 18 deletions

View File

@ -41379,6 +41379,473 @@ Body:
SplashArea: 6
Requires:
SpCost: 1
- Id: 5401
Name: NW_P_F_I
Description: P.F.I
MaxLevel: 10
- Id: 5402
Name: NW_GRENADE_MASTERY
Description: Grenade Mastery
MaxLevel: 10
- Id: 5403
Name: NW_INTENSIVE_AIM
Description: Intensive Aim
MaxLevel: 1
Type: Weapon
TargetType: Self
DamageFlags:
NoDamage: true
Hit: Single
HitCount: 1
Duration1: -1
Requires:
SpCost:
- Level: 1
Amount: 10
Status: Intensive_Aim
- Id: 5404
Name: NW_GRENADE_FRAGMENT
Description: Grenade Fragment
MaxLevel: 7
Type: Weapon
TargetType: Self
DamageFlags:
NoDamage: true
Hit: Single
HitCount: 1
Duration1: 300000
Cooldown: 2000
Requires:
SpCost: 50
- Id: 5405
Name: NW_THE_VIGILANTE_AT_NIGHT
Description: The Vigilante at Night
MaxLevel: 5
Type: Weapon
TargetType: Self
DamageFlags:
Splash: true
Hit: Multi_Hit
HitCount: 4
Element: Weapon
SplashArea:
- Level: 1
Area: 2
- Level: 2
Area: 2
- Level: 3
Area: 2
- Level: 4
Area: 3
- Level: 5
Area: 3
GiveAp: 1
AfterCastActDelay: 1000
Cooldown: 500
CastCancel: true
FixedCastTime: 1500
Requires:
SpCost:
- Level: 1
Amount: 49
- Level: 2
Amount: 53
- Level: 3
Amount: 57
- Level: 4
Amount: 61
- Level: 5
Amount: 65
Weapon:
Gatling: true
Shotgun: true
Ammo:
Bullet: true
AmmoAmount: 10
- Id: 5406
Name: NW_ONLY_ONE_BULLET
Description: Only One Bullet
MaxLevel: 5
Type: Weapon
TargetType: Attack
DamageFlags:
Critical: true
Range: -9
Hit: Single
HitCount: 1
Element: Weapon
GiveAp: 1
AfterCastActDelay: 500
Cooldown: 300
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 39
- Level: 2
Amount: 43
- Level: 3
Amount: 47
- Level: 4
Amount: 51
- Level: 5
Amount: 55
Weapon:
Revolver: true
Rifle: true
Ammo:
Bullet: true
AmmoAmount: 1
- Id: 5407
Name: NW_SPIRAL_SHOOTING
Description: Spiral Shooting
MaxLevel: 5
Type: Weapon
TargetType: Attack
DamageFlags:
Critical: true
Splash: true
Range: -9
Hit: Multi_Hit
HitCount: 1
Element: Weapon
SplashArea:
- Level: 1
Area: 2
- Level: 2
Area: 2
- Level: 3
Area: 2
- Level: 4
Area: 3
- Level: 5
Area: 3
GiveAp: 1
AfterCastActDelay: 1000
Cooldown: 500
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 48
- Level: 2
Amount: 53
- Level: 3
Amount: 58
- Level: 4
Amount: 63
- Level: 5
Amount: 68
Weapon:
Grenade: true
Rifle: true
Ammo:
Bullet: true
AmmoAmount: 6
- Id: 5408
Name: NW_MAGAZINE_FOR_ONE
Description: Magazine for One
MaxLevel: 5
Type: Weapon
TargetType: Attack
DamageFlags:
Critical: true
Range: -9
Hit: Multi_Hit
HitCount: 6
Element: Weapon
GiveAp: 1
AfterCastActDelay: 1000
Cooldown: 500
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 42
- Level: 2
Amount: 46
- Level: 3
Amount: 50
- Level: 4
Amount: 54
- Level: 5
Amount: 58
Weapon:
Revolver: true
Gatling: true
Ammo:
Bullet: true
AmmoAmount: 6
- Id: 5409
Name: NW_WILD_FIRE
Description: Wild Fire
MaxLevel: 5
Type: Weapon
TargetType: Ground
Range: -9
Hit: Single
HitCount: -3
Element: Weapon
DamageFlags:
Splash: true
SplashArea:
- Level: 1
Area: 2
- Level: 2
Area: 2
- Level: 3
Area: 2
- Level: 4
Area: 3
- Level: 5
Area: 3
GiveAp: 1
AfterCastActDelay: 1000
Cooldown: 500
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 51
- Level: 2
Amount: 55
- Level: 3
Amount: 59
- Level: 4
Amount: 63
- Level: 5
Amount: 67
Weapon:
Shotgun: true
Grenade: true
Ammo:
Bullet: true
AmmoAmount: 5
- Id: 5410
Name: NW_BASIC_GRENADE
Description: Basic Grenade
MaxLevel: 5
Type: Weapon
TargetType: Ground
Range: -9
Hit: Single
HitCount: -2
Element: Weapon
DamageFlags:
Splash: true
SplashArea:
- Level: 1
Area: 1
- Level: 2
Area: 1
- Level: 3
Area: 1
- Level: 4
Area: 2
- Level: 5
Area: 2
GiveAp: 2
Cooldown: 300
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 36
- Level: 2
Amount: 42
- Level: 3
Amount: 48
- Level: 4
Amount: 54
- Level: 5
Amount: 60
ItemCost:
- Item: Nw_Grenade
Amount: 1
- Id: 5411
Name: NW_HASTY_FIRE_IN_THE_HOLE
Description: Hasty Fire in the Hole
MaxLevel: 5
Type: Weapon
TargetType: Ground
Range: -9
Hit: Multi_Hit
HitCount: -2
Element: Weapon
DamageFlags:
Splash: true
SplashArea: 2
GiveAp: 3
Cooldown: 1000
CastCancel: true
FixedCastTime: 1000
AfterCastActDelay: 1500
Requires:
SpCost:
- Level: 1
Amount: 50
- Level: 2
Amount: 53
- Level: 3
Amount: 56
- Level: 4
Amount: 59
- Level: 5
Amount: 62
ItemCost:
- Item: Nw_Grenade
Amount: 3
- Id: 5412
Name: NW_GRENADES_DROPPING
Description: Grenades Dropping
MaxLevel: 5
Type: Weapon
TargetType: Ground
Range: -9
Hit: Multi_Hit
HitCount: 3
Element: Weapon
DamageFlags:
Splash: true
SplashArea:
- Level: 1
Area: 5
- Level: 2
Area: 5
- Level: 3
Area: 5
- Level: 4
Area: 4
- Level: 5
Area: 4
GiveAp: 5
Cooldown: 4500
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost:
- Level: 1
Amount: 60
- Level: 2
Amount: 66
- Level: 3
Amount: 72
- Level: 4
Amount: 78
- Level: 5
Amount: 84
ItemCost:
- Item: Nw_Grenade
Amount: 15
Duration1: 4000
Duration2: 100
Unit:
Id: Grenades_Dropping
Layout: 0
Range:
- Level: 1
Size: 1
- Level: 2
Size: 1
- Level: 3
Size: 1
- Level: 4
Size: 2
- Level: 5
Size: 2
Interval: 250
Target: Enemy
Flag:
NoOverlap: true
PathCheck: true
- Id: 5413
Name: NW_AUTO_FIRING_LAUNCHER
Description: Auto Firing Launcher
MaxLevel: 5
Type: Weapon
TargetType: Self
DamageFlags:
NoDamage: true
Duration1:
- Level: 1
Time: 120000
- Level: 2
Time: 150000
- Level: 3
Time: 180000
- Level: 4
Time: 210000
- Level: 5
Time: 240000
Cooldown: 30000
CastCancel: true
FixedCastTime: 3000
Requires:
SpCost:
- Level: 1
Amount: 90
- Level: 2
Amount: 100
- Level: 3
Amount: 110
- Level: 4
Amount: 120
- Level: 5
Amount: 130
Status: Auto_Firing_Launcher
- Id: 5414
Name: NW_HIDDEN_CARD
Description: Hidden Card
MaxLevel: 10
Type: Weapon
TargetType: Self
DamageFlags:
NoDamage: true
Duration1: 300000
Cooldown: 60000
CastCancel: true
FixedCastTime: 2000
Requires:
SpCost: 150
ApCost: 150
Status: Hidden_Card
- Id: 5415
Name: NW_MISSION_BOMBARD
Description: Mission Bombard
MaxLevel: 10
Type: Weapon
TargetType: Ground
Range: -9
Hit: Multi_Hit
HitCount: -3
Element: Weapon
DamageFlags:
Splash: true
SplashArea: 4
Cooldown: 10000
CastCancel: true
FixedCastTime: 1000
Requires:
SpCost: 100
ApCost: 35
ItemCost:
- Item: Nw_Grenade
Amount: 15
Duration1: 10000
Unit:
Id: Mission_Bombard
Layout: 0
Range: 2
Interval: 250
Target: Enemy
Flag:
NoOverlap: true
PathCheck: true
- Id: 5449
Name: HN_SELFSTUDY_TATICS
Description: Self Study Tactics
@ -42159,6 +42626,16 @@ Body:
SpCost: 150
ApCost: 150
Status: Rulebreak
- Id: 5496
Name: NW_THE_VIGILANTE_AT_NIGHT_GUN_GATLING
Description: The Vigilante At Night Gun Gatling
MaxLevel: 5
CastCancel: true
- Id: 5497
Name: NW_THE_VIGILANTE_AT_NIGHT_GUN_SHOTGUN
Description: The Vigilante At Night Gun Shotgun
MaxLevel: 5
CastCancel: true
- Id: 6001
Name: DK_DRAGONIC_BREATH
Description: Dragonic Breath

View File

@ -7864,6 +7864,95 @@ Body:
Royal_Guard: true
Royal_Guard_T: true
Imperial_Guard: true
- Job: Night_Watch
Inherit:
Novice: true
Gunslinger: true
Rebellion: true
Tree:
- Name: NW_P_F_I
MaxLevel: 10
- Name: NW_GRENADE_MASTERY
MaxLevel: 10
- Name: NW_INTENSIVE_AIM
MaxLevel: 1
Requires:
- Name: NW_P_F_I
Level: 1
- Name: NW_HIDDEN_CARD
MaxLevel: 10
Requires:
- Name: NW_P_F_I
Level: 5
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_BASIC_GRENADE
MaxLevel: 5
Requires:
- Name: NW_GRENADE_MASTERY
Level: 3
- Name: NW_GRENADE_FRAGMENT
MaxLevel: 7
Requires:
- Name: NW_GRENADE_MASTERY
Level: 1
- Name: NW_THE_VIGILANTE_AT_NIGHT
MaxLevel: 5
Requires:
- Name: NW_P_F_I
Level: 3
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_ONLY_ONE_BULLET
MaxLevel: 5
Requires:
- Name: NW_P_F_I
Level: 3
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_SPIRAL_SHOOTING
MaxLevel: 5
Requires:
- Name: NW_P_F_I
Level: 3
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_MAGAZINE_FOR_ONE
MaxLevel: 5
Requires:
- Name: NW_P_F_I
Level: 3
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_WILD_FIRE
MaxLevel: 5
Requires:
- Name: NW_P_F_I
Level: 3
- Name: NW_INTENSIVE_AIM
Level: 1
- Name: NW_HASTY_FIRE_IN_THE_HOLE
MaxLevel: 5
Requires:
- Name: NW_BASIC_GRENADE
Level: 3
- Name: NW_GRENADES_DROPPING
MaxLevel: 5
Requires:
- Name: NW_HASTY_FIRE_IN_THE_HOLE
Level: 3
- Name: NW_AUTO_FIRING_LAUNCHER
MaxLevel: 5
Requires:
- Name: NW_GRENADES_DROPPING
Level: 3
- Name: NW_MISSION_BOMBARD
MaxLevel: 10
Requires:
- Name: NW_GRENADE_MASTERY
Level: 5
- Name: NW_GRENADES_DROPPING
Level: 3
- Job: Hyper_Novice
Inherit:
Novice: true

View File

@ -8787,3 +8787,92 @@ Body:
- Status: Rulebreak
Icon: EFST_RULEBREAK
DurationLookup: HN_RULEBREAK
- Status: Intensive_Aim
Icon: EFST_INTENSIVE_AIM
States:
NoMove: true
CalcFlags:
Batk: true
Hit: true
Cri: true
Flags:
BlEffect: true
DisplayPc: true
SendVal1: true
NoSave: true
NoBanishingBuster: true
NoDispell: true
NoClearance: true
- Status: Intensive_Aim_Count
Icon: EFST_INTENSIVE_AIM_COUNT
Flags:
DisplayPc: true
SendVal1: true
NoSave: true
NoBanishingBuster: true
NoDispell: true
NoClearance: true
- Status: Grenade_Fragment_1
Icon: EFST_GRENADE_FRAGMENT_1
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_2: true
Grenade_Fragment_3: true
Grenade_Fragment_4: true
Grenade_Fragment_5: true
Grenade_Fragment_6: true
- Status: Grenade_Fragment_2
Icon: EFST_GRENADE_FRAGMENT_2
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_1: true
Grenade_Fragment_3: true
Grenade_Fragment_4: true
Grenade_Fragment_5: true
Grenade_Fragment_6: true
- Status: Grenade_Fragment_3
Icon: EFST_GRENADE_FRAGMENT_3
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_1: true
Grenade_Fragment_2: true
Grenade_Fragment_4: true
Grenade_Fragment_5: true
Grenade_Fragment_6: true
- Status: Grenade_Fragment_4
Icon: EFST_GRENADE_FRAGMENT_4
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_1: true
Grenade_Fragment_2: true
Grenade_Fragment_3: true
Grenade_Fragment_5: true
Grenade_Fragment_6: true
- Status: Grenade_Fragment_5
Icon: EFST_GRENADE_FRAGMENT_5
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_1: true
Grenade_Fragment_2: true
Grenade_Fragment_3: true
Grenade_Fragment_4: true
Grenade_Fragment_6: true
- Status: Grenade_Fragment_6
Icon: EFST_GRENADE_FRAGMENT_6
DurationLookup: NW_GRENADE_FRAGMENT
EndOnStart:
Grenade_Fragment_1: true
Grenade_Fragment_2: true
Grenade_Fragment_3: true
Grenade_Fragment_4: true
Grenade_Fragment_5: true
- Status: Auto_Firing_Launcher
Icon: EFST_AUTO_FIRING_LAUNCHEREFST
DurationLookup: NW_AUTO_FIRING_LAUNCHER
Flags:
SendVal1: true
- Status: Hidden_Card
Icon: EFST_HIDDEN_CARD
DurationLookup: NW_HIDDEN_CARD
CalcFlags:
All: true

View File

@ -2585,12 +2585,20 @@ void battle_consume_ammo(map_session_data*sd, int skill, int lv)
{
int qty = 1;
if( sd == nullptr ){
return;
}
if (!battle_config.arrow_decrement)
return;
if (skill) {
qty = skill_get_ammo_qty(skill, lv);
if (!qty) qty = 1;
if( skill == NW_MAGAZINE_FOR_ONE && sd->weapontype1 == W_GATLING ){
qty += 4;
}
}
if (sd->equip_index[EQI_AMMO] >= 0) //Qty check should have been done in skill_check_condition
@ -2621,6 +2629,7 @@ static int battle_range_type(struct block_list *src, struct block_list *target,
case BO_ACIDIFIED_ZONE_FIRE_ATK:
case BO_ACIDIFIED_ZONE_GROUND_ATK:
case BO_ACIDIFIED_ZONE_WIND_ATK:
case NW_THE_VIGILANTE_AT_NIGHT:
return BF_LONG;
case NJ_KIRIKAGE: // Cast range mimics NJ_SHADOWJUMP but damage is considered melee
case GC_CROSSIMPACT: // Cast range is 7 cells and player jumps to target but skill is considered melee
@ -2997,6 +3006,18 @@ static bool is_attack_critical(struct Damage* wd, struct block_list *src, struct
case WH_GALESTORM:
if (sc && !sc->getSCE(SC_CALAMITYGALE))
return false;
break;
case NW_ONLY_ONE_BULLET:
case NW_SPIRAL_SHOOTING:
if( sd == nullptr || sd->weapontype1 != W_RIFLE ){
return false;
}
break;
case NW_MAGAZINE_FOR_ONE:
if( sd == nullptr || sd->weapontype1 != W_REVOLVER ){
return false;
}
break;
}
if(tsd && tsd->bonus.critical_def)
cri = cri * ( 100 - tsd->bonus.critical_def ) / 100;
@ -3282,8 +3303,25 @@ static bool attack_ignores_def(struct Damage* wd, struct block_list *src, struct
if (sc && sc->getSCE(SC_FUSION))
return true;
if (skill_id == RK_WINDCUTTER && sd && sd->status.weapon == W_2HSWORD)
return true;
if( sd != nullptr ){
switch( skill_id ){
case RK_WINDCUTTER:
if( sd->status.weapon == W_2HSWORD ){
return true;
}
break;
case NW_THE_VIGILANTE_AT_NIGHT:
if( sd->status.weapon == W_GATLING ){
return true;
}
break;
case NW_ONLY_ONE_BULLET:
if( sd->status.weapon == W_REVOLVER ){
return true;
}
break;
}
}
if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS)
{ //Ignore Defense?
@ -3427,6 +3465,27 @@ int battle_get_weapon_element(struct Damage* wd, struct block_list *src, struct
if (sd && sd->flicker) //Force RL_H_MINE deals fire damage if activated by RL_FLICKER
element = ELE_FIRE;
break;
case NW_BASIC_GRENADE:
case NW_HASTY_FIRE_IN_THE_HOLE:
case NW_GRENADES_DROPPING:
case NW_MISSION_BOMBARD:
// Night Watch Grenade Fragment elementals affecting those skills.
if( sc != nullptr ){
if( sc->getSCE( SC_GRENADE_FRAGMENT_1 ) != nullptr ){
element = ELE_WATER;
}else if( sc->getSCE( SC_GRENADE_FRAGMENT_2 ) != nullptr ){
element = ELE_WIND;
}else if( sc->getSCE( SC_GRENADE_FRAGMENT_3 ) != nullptr ){
element = ELE_EARTH;
}else if( sc->getSCE( SC_GRENADE_FRAGMENT_4 ) != nullptr ){
element = ELE_FIRE;
}else if( sc->getSCE( SC_GRENADE_FRAGMENT_5 ) != nullptr ){
element = ELE_DARK;
}else if( sc->getSCE( SC_GRENADE_FRAGMENT_6 ) != nullptr ){
element = ELE_HOLY;
}
}
break;
}
if (sc && sc->getSCE(SC_GOLDENE_FERSE) && ((!skill_id && (rnd() % 100 < sc->getSCE(SC_GOLDENE_FERSE)->val4)) || skill_id == MH_STAHL_HORN))
@ -4186,6 +4245,18 @@ static void battle_calc_multi_attack(struct Damage* wd, struct block_list *src,s
}
break;
#endif
case NW_SPIRAL_SHOOTING:
if (sd && sd->weapontype1 == W_GRENADE)
wd->div_ += 1;
break;
case NW_MAGAZINE_FOR_ONE:
if (sd && sd->weapontype1 == W_GATLING)
wd->div_ += 4;
break;
case NW_THE_VIGILANTE_AT_NIGHT:
if (sd && sd->weapontype1 == W_GATLING)
wd->div_ += 3;
break;
}
}
@ -5864,6 +5935,85 @@ static int battle_calc_attack_skill_ratio(struct Damage* wd, struct block_list *
skillratio += 5 * sstatus->pow;
RE_LVL_DMOD(100);
break;
case NW_HASTY_FIRE_IN_THE_HOLE:
skillratio += -100 + 1500 + 1050 * skill_lv;
skillratio += pc_checkskill( sd, NW_GRENADE_MASTERY ) * 20;
skillratio += 5 * sstatus->con;
RE_LVL_DMOD(100);
break;
case NW_BASIC_GRENADE:
skillratio += -100 + 1000 + 950 * skill_lv;
skillratio += pc_checkskill( sd, NW_GRENADE_MASTERY ) * 50;
skillratio += 5 * sstatus->con;
RE_LVL_DMOD(100);
break;
case NW_GRENADES_DROPPING:
skillratio += -100 + 550 + 850 * skill_lv;
skillratio += pc_checkskill( sd, NW_GRENADE_MASTERY ) * 30;
skillratio += 5 * sstatus->con;
RE_LVL_DMOD(100);
break;
case NW_WILD_FIRE:
skillratio += -100 + 1000 + 2300 * skill_lv;
skillratio += 5 * sstatus->con;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 500 * skill_lv;
if (sd && sd->weapontype1 == W_SHOTGUN)
skillratio += 150 * skill_lv;
RE_LVL_DMOD(100);
break;
case NW_MAGAZINE_FOR_ONE:
skillratio += -100 + 100 + 450 * ( skill_lv - 1 );
skillratio += 5 * sstatus->con;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 100 * skill_lv;
if (sd && sd->weapontype1 == W_REVOLVER)
skillratio += 50 + 100 * (skill_lv-1);
RE_LVL_DMOD(100);
break;
case NW_SPIRAL_SHOOTING:
skillratio += -100 + 1000 + 1500 * skill_lv;
skillratio += 5 * sstatus->con;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 150 * skill_lv;
if (sd && sd->weapontype1 == W_RIFLE)
skillratio += 200 + 200 * skill_lv;
RE_LVL_DMOD(100);
break;
case NW_ONLY_ONE_BULLET:
skillratio += -100 + 800 + 1350 * skill_lv;
skillratio += 5 * sstatus->con;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 350 * skill_lv;
if (sd && sd->weapontype1 == W_REVOLVER) {
skillratio += 150 * skill_lv;
}
RE_LVL_DMOD(100);
break;
case NW_THE_VIGILANTE_AT_NIGHT:
if (sd && sd->weapontype1 == W_GATLING) {
skillratio += -100 + 300 * skill_lv;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 100 * skill_lv;
} else {
skillratio += -100 + 800 + 700 * skill_lv;
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
skillratio += sc->getSCE(SC_INTENSIVE_AIM_COUNT)->val1 * 200 * skill_lv;
}
skillratio += 5 * sstatus->con;
RE_LVL_DMOD(100);
break;
case NW_MISSION_BOMBARD:
if( wd->miscflag&SKILL_ALTDMG_FLAG ){
skillratio += -100 + 5000 + 1800 * skill_lv;
skillratio += pc_checkskill( sd, NW_GRENADE_MASTERY ) * 100;
}else{
skillratio += -100 + 800 + 200 * skill_lv;
skillratio += pc_checkskill( sd, NW_GRENADE_MASTERY ) * 30;
}
skillratio += 5 * sstatus->con;
RE_LVL_DMOD(100);
break;
}
return skillratio;
}
@ -6089,6 +6239,8 @@ static void battle_attack_sc_bonus(struct Damage* wd, struct block_list *src, st
if (sc->getSCE(SC_MIRACLE))
anger_id = 2; // Always treat all monsters as star flagged monster when in miracle state
if (sc->getSCE(SC_HIDDEN_CARD) && (wd->flag&BF_LONG) == BF_LONG)
RE_ALLATK_ADDRATE(wd, sc->getSCE(SC_HIDDEN_CARD)->val3);
}
if ((wd->flag&(BF_LONG|BF_MAGIC)) == BF_LONG) {
@ -9773,6 +9925,113 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
sd->state.autocast = 0;
}
if( sc->getSCE( SC_AUTO_FIRING_LAUNCHER ) ){
uint16 skill_id;
uint16 skill_lv;
switch( sc->getSCE( SC_AUTO_FIRING_LAUNCHER )->val1 ){
case 1:
skill_id = NW_BASIC_GRENADE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 6, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
break;
case 2:
skill_id = NW_BASIC_GRENADE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 7, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
break;
case 3:
skill_id = NW_HASTY_FIRE_IN_THE_HOLE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 3, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
skill_id = NW_BASIC_GRENADE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 8, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
break;
case 4:
skill_id = NW_HASTY_FIRE_IN_THE_HOLE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 5, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
skill_id = NW_BASIC_GRENADE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 9, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
break;
case 5:
skill_id = NW_GRENADES_DROPPING;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 3, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
skill_id = NW_HASTY_FIRE_IN_THE_HOLE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 7, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
skill_id = NW_BASIC_GRENADE;
skill_lv = pc_checkskill( sd, skill_id );
if( skill_lv > 0 && rnd_chance( 10, 100 ) ){
sd->state.autocast = 1;
skill_castend_pos2( src, target->x, target->y, skill_id, skill_lv, tick, flag );
battle_autocast_aftercast( src, skill_id, skill_lv, tick );
sd->state.autocast = 0;
}
break;
}
}
// Autocasted skills from super elemental supportive buffs.
if (sc->getSCE(SC_FLAMETECHNIC_OPTION) && rnd() % 100 < 7)
battle_autocast_elembuff_skill(sd, target, MG_FIREBOLT, tick, flag);

View File

@ -1900,6 +1900,16 @@
export_constant(SC_GROUNDGRAVITY);
export_constant(SC_BREAKINGLIMIT);
export_constant(SC_RULEBREAK);
export_constant(SC_INTENSIVE_AIM);
export_constant(SC_INTENSIVE_AIM_COUNT);
export_constant(SC_GRENADE_FRAGMENT_1);
export_constant(SC_GRENADE_FRAGMENT_2);
export_constant(SC_GRENADE_FRAGMENT_3);
export_constant(SC_GRENADE_FRAGMENT_4);
export_constant(SC_GRENADE_FRAGMENT_5);
export_constant(SC_GRENADE_FRAGMENT_6);
export_constant(SC_AUTO_FIRING_LAUNCHER);
export_constant(SC_HIDDEN_CARD);
#ifdef RENEWAL
export_constant(SC_EXTREMITYFIST2);

View File

@ -4794,6 +4794,29 @@ static TIMER_FUNC(skill_timerskill){
skill_unitsetting(src, skl->skill_id, skl->skill_lv, tmpx, tmpy, skill_get_unit_interval(skl->skill_id));
}
break;
case NW_HASTY_FIRE_IN_THE_HOLE:
skill_castend_pos2(src, skl->x, skl->y, skl->skill_id, skl->skill_lv, tick, skl->flag);
break;
case NW_GRENADES_DROPPING: {
int area = skill_get_splash(skl->skill_id, skl->skill_lv);
short tmpx = 0, tmpy = 0;
tmpx = skl->x - area + rnd() % (area * 2 + 1);
tmpy = skl->y - area + rnd() % (area * 2 + 1);
skill_unitsetting(src, skl->skill_id, skl->skill_lv, tmpx, tmpy, skl->flag);
}
break;
case NW_MISSION_BOMBARD: {
int area = skill_get_unit_range(skl->skill_id, skl->skill_lv);
int range = skill_get_splash(skl->skill_id, skl->skill_lv);
short tmpx = 0, tmpy = 0;
tmpx = skl->x - range + rnd() % (range * 2 + 1);
tmpy = skl->y - range + rnd() % (range * 2 + 1);
map_foreachinarea(skill_area_sub, src->m, tmpx - range, tmpy - range, tmpx + range, tmpy + range, BL_CHAR,
src, skl->skill_id, skl->skill_lv, tick, skl->flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
}
break;
}
}
} while (0);
@ -5235,6 +5258,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case ABR_DUAL_CANNON_FIRE:
case ABR_INFINITY_BUSTER:
case MT_TRIPLE_LASER:
case NW_MISSION_BOMBARD:
case NW_HASTY_FIRE_IN_THE_HOLE:
case NW_BASIC_GRENADE:
case NW_WILD_FIRE:
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
break;
case DK_DRAGONIC_AURA:
@ -5916,6 +5943,24 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
}
}
break;
case NW_THE_VIGILANTE_AT_NIGHT:
if (flag & 1)
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
break;
case NW_SPIRAL_SHOOTING:
if (flag & 1) {
skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
} else {
int splash = skill_get_splash(skill_id, skill_lv);
if (sd && sd->weapontype1 == W_GRENADE)
splash += 2;
clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
map_foreachinrange(skill_area_sub, bl, splash, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
}
break;
//Place units around target
case NJ_BAKUENRYU:
@ -7077,6 +7122,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
}
break;
case NW_MAGAZINE_FOR_ONE:
case NW_ONLY_ONE_BULLET:
skill_attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
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,
@ -7101,7 +7153,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
}
// perform skill requirement consumption
skill_consume_requirement(sd,skill_id,skill_lv,2);
if (!(flag&SKILL_NOCONSUME_REQ))
skill_consume_requirement(sd,skill_id,skill_lv,2);
}
return 0;
@ -7297,6 +7350,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
type = skill_get_sc(skill_id);
tsc = status_get_sc(bl);
status_change* sc = status_get_sc(src);
tsce = (tsc && type != SC_NONE)?tsc->getSCE(type):NULL;
if (src!=bl && type > SC_NONE &&
@ -7651,8 +7705,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
return 1;
}
status_change* sc = status_get_sc(src);
if( sc && tsc )
{
if( !sc->getSCE(SC_MARIONETTE) && !tsc->getSCE(SC_MARIONETTE2) )
@ -8025,7 +8077,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
sc_start(src, bl, type, 100, skill_lv, skill_get_time2(skill_id, skill_lv));
} else {
uint16 climax_lv = 0, splash_size = skill_get_splash(skill_id, skill_lv);
status_change *sc = status_get_sc(src);
if (sc && sc->getSCE(SC_CLIMAX))
climax_lv = sc->getSCE(SC_CLIMAX)->val1;
@ -8566,7 +8617,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case ABC_ABYSS_DAGGER:
case BO_EXPLOSIVE_POWDER:
{
status_change *sc = status_get_sc(src);
int starget = BL_CHAR|BL_SKILL;
if (skill_id == SR_HOWLINGOFLION)
@ -11176,8 +11226,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case WL_SUMMONWB:
case WL_SUMMONSTONE:
{
status_change *sc = status_get_sc(src);
if (sc == nullptr)
break;
@ -11687,7 +11735,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case WM_LERADS_DEW:
case WM_UNLIMITED_HUMMING_VOICE:
if( flag&1 ) { // These affect to to all party members near the caster.
status_change *sc = status_get_sc(src);
if( sc && sc->getSCE(type) ) {
sc_start2(src,bl,type,100,skill_lv,pc_checkskill(sd, WM_LESSON),skill_get_time(skill_id,skill_lv));
}
@ -12094,9 +12141,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
s_elemental_data *ele = BL_CAST(BL_ELEM, src);
if( ele ) {
sc_type type2 = (sc_type)(type-1);
status_change *sc = status_get_sc(&ele->bl);
status_change *esc = status_get_sc(&ele->bl);
if( (sc && sc->getSCE(type2)) || (tsc && tsc->getSCE(type)) ) {
if( (esc && esc->getSCE(type2)) || (tsc && tsc->getSCE(type)) ) {
status_change_end(src,type);
status_change_end(bl,type2);
} else {
@ -12121,11 +12168,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case EL_WATER_SCREEN: {
s_elemental_data *ele = BL_CAST(BL_ELEM, src);
if( ele ) {
status_change *sc = status_get_sc(&ele->bl);
status_change *esc = status_get_sc(&ele->bl);
sc_type type2 = (sc_type)(type-1);
clif_skill_nodamage(src,src,skill_id,skill_lv,1);
if( (sc && sc->getSCE(type2)) || (tsc && tsc->getSCE(type)) ) {
if( (esc && esc->getSCE(type2)) || (tsc && tsc->getSCE(type)) ) {
status_change_end(bl,type);
status_change_end(src,type2);
} else {
@ -12865,6 +12912,54 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
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_damage_id);
break;
case NW_THE_VIGILANTE_AT_NIGHT:
i = skill_get_splash(skill_id, skill_lv);
skill_area_temp[0] = 0;
skill_area_temp[1] = bl->id;
skill_area_temp[2] = 0;
if (sd && sd->weapontype1 == W_GATLING) {
i += 3;
clif_skill_nodamage(src, bl, NW_THE_VIGILANTE_AT_NIGHT_GUN_GATLING, skill_lv, 1);
} else
clif_skill_nodamage(src, bl, NW_THE_VIGILANTE_AT_NIGHT_GUN_SHOTGUN, skill_lv, 1);
map_foreachinrange(skill_area_sub, bl, i, BL_CHAR, src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill_castend_damage_id);
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
break;
case NW_INTENSIVE_AIM:
if (tsc && tsc->getSCE(type)) {
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
status_change_end(bl, type);
} else {
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
}
clif_skill_nodamage(src, src, skill_id, skill_lv, 1);
break;
case NW_HIDDEN_CARD:
case NW_AUTO_FIRING_LAUNCHER:
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
clif_skill_nodamage(src, src, skill_id, skill_lv, 1);
break;
case NW_GRENADE_FRAGMENT:
status_change_end(src, type);
if (skill_lv < 7)
sc_start(src, bl, (sc_type)(SC_GRENADE_FRAGMENT_1 -1 + skill_lv), 100, skill_lv, skill_get_time(skill_id, skill_lv));
else if (skill_lv == 7) {
status_change_end(src, SC_GRENADE_FRAGMENT_1);
status_change_end(src, SC_GRENADE_FRAGMENT_2);
status_change_end(src, SC_GRENADE_FRAGMENT_3);
status_change_end(src, SC_GRENADE_FRAGMENT_4);
status_change_end(src, SC_GRENADE_FRAGMENT_5);
status_change_end(src, SC_GRENADE_FRAGMENT_6);
}
clif_skill_nodamage(src, src, skill_id, skill_lv, 1);
break;
default: {
std::shared_ptr<s_skill_db> skill = skill_db.find(skill_id);
ShowWarning("skill_castend_nodamage_id: missing code case for skill %s(%d)\n", skill ? skill->name : "UNKNOWN", skill_id);
@ -12875,8 +12970,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
if (skill_id != SR_CURSEDCIRCLE && skill_id != NPC_SR_CURSEDCIRCLE) {
status_change *sc = status_get_sc(src);
if (sc && sc->getSCE(SC_CURSEDCIRCLE_ATKER)) // Should only remove after the skill had been casted.
status_change_end(src,SC_CURSEDCIRCLE_ATKER);
}
@ -12896,7 +12989,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
skill_onskillusage(sd, bl, skill_id, tick);
// perform skill requirement consumption
skill_consume_requirement(sd,skill_id,skill_lv,2);
if (!(flag&SKILL_NOCONSUME_REQ))
skill_consume_requirement(sd,skill_id,skill_lv,2);
}
map_freeblock_unlock();
@ -13603,6 +13697,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case SU_CN_METEOR:
case NPC_RAINOFMETEOR:
case HN_METEOR_STORM_BUSTER:
case NW_GRENADES_DROPPING:
break; //Effect is displayed on respective switch case.
default:
if(skill_get_inf(skill_id)&INF_SELF_SKILL)
@ -13643,6 +13738,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
break;
case SR_RIDEINLIGHTNING:
case NW_BASIC_GRENADE:
i = skill_get_splash(skill_id, skill_lv);
map_foreachinallarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR,
src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id);
@ -14545,6 +14641,53 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
}
break;
case NW_WILD_FIRE:
i = skill_get_splash(skill_id, skill_lv);
if (sd && sd->status.weapon == W_GRENADE)
i += 2;
map_foreachinallarea(skill_area_sub,
src->m, x - i, y - i, x + i, y + i, BL_CHAR,
src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1,
skill_castend_damage_id);
if (sc && sc->getSCE(SC_INTENSIVE_AIM_COUNT))
status_change_end(src, SC_INTENSIVE_AIM_COUNT);
break;
case NW_HASTY_FIRE_IN_THE_HOLE:
i = skill_get_splash(skill_id, skill_lv);
if (flag & 1){
i++;
}
if (flag & 2){
i++;
}
map_foreachinallarea(skill_area_sub,
src->m, x - i, y - i, x + i, y + i, BL_CHAR,
src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1,
skill_castend_damage_id);
if (!(flag & 1)) {
skill_addtimerskill(src, tick + 300, 0, x, y, skill_id, skill_lv, 0, flag | 1 | SKILL_NOCONSUME_REQ);
skill_addtimerskill(src, tick + 600, 0, x, y, skill_id, skill_lv, 0, flag | 3 | SKILL_NOCONSUME_REQ);
}
break;
case NW_GRENADES_DROPPING: {
uint16 splash = skill_get_splash(skill_id, skill_lv);
uint16 tmpx = rnd_value( x - splash, x + splash );
uint16 tmpy = rnd_value( y - splash, y + splash );
skill_unitsetting(src, skill_id, skill_lv, tmpx, tmpy, flag);
for (i = 0; i <= (skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id)); i++) {
skill_addtimerskill(src, tick + (t_tick)i*skill_get_unit_interval(skill_id), 0, x, y, skill_id, skill_lv, 0, flag);
}
} break;
case NW_MISSION_BOMBARD:
i = skill_get_splash(skill_id,skill_lv);
map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SKILL_ALTDMG_FLAG|1,skill_castend_damage_id);
skill_unitsetting(src, skill_id, skill_lv, x, y, flag);
for (i = 1; i <= (skill_get_time(skill_id, skill_lv) / skill_get_unit_interval(skill_id)); i++) {
skill_addtimerskill(src, tick + (t_tick)i*skill_get_unit_interval(skill_id), 0, x, y, skill_id, skill_lv, 0, flag);
}
break;
default:
ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id);
return 1;
@ -14563,7 +14706,8 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
}
skill_onskillusage(sd, NULL, skill_id, tick);
// perform skill requirement consumption
skill_consume_requirement(sd,skill_id,skill_lv,2);
if (!(flag&SKILL_NOCONSUME_REQ))
skill_consume_requirement(sd,skill_id,skill_lv,2);
}
return 0;
@ -15211,6 +15355,10 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui
case WH_FLAMETRAP:
limit += 3000 * (sd ? pc_checkskill(sd, WH_ADVANCED_TRAP) : 5);
break;
case NW_GRENADES_DROPPING:
limit = skill_get_time2(skill_id,skill_lv);
break;
}
// Init skill unit group
@ -18711,6 +18859,8 @@ struct s_skill_condition skill_get_requirement(map_session_data* sd, uint16 skil
req.mhp = skill->require.mhp[skill_lv-1];
req.weapon = skill->require.weapon;
req.ammo_qty = skill->require.ammo_qty[skill_lv-1];
if (skill_id == NW_MAGAZINE_FOR_ONE && sd->weapontype1 == W_GATLING)
req.ammo_qty += 4;
if (req.ammo_qty)
req.ammo = skill->require.ammo;

View File

@ -41,6 +41,8 @@ class status_change;
/// To control alternative skill scalings
#define SKILL_ALTDMG_FLAG 0x10
/// Make skill ignore requirement consumption [Muh]
#define SKILL_NOCONSUME_REQ 0x20
/// Constants to identify a skill's nk value (damage properties)
/// The NK value applies only to non INF_GROUND_SKILL skills

View File

@ -4169,6 +4169,10 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
base_status->mdef++;
}
// ----- CONCENTRATION CALCULATION -----
if ((skill = pc_checkskill(sd, NW_GRENADE_MASTERY)) > 0)
base_status->con += skill;
// ------ ATTACK CALCULATION ------
// Base batk value is set in status_calc_misc
@ -4383,6 +4387,8 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
base_status->patk += skill;
if ((skill = pc_checkskill(sd, HN_SELFSTUDY_SOCERY)) > 0)
base_status->smatk += skill;
if ((skill = pc_checkskill(sd, NW_P_F_I)) > 0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE))
base_status->patk += skill + 2;
// 2-Handed Staff Mastery
if( sd->status.weapon == W_2HSTAFF && ( skill = pc_checkskill( sd, AG_TWOHANDSTAFF ) ) > 0 ){
@ -4759,6 +4765,8 @@ int status_calc_pc_sub(map_session_data* sd, uint8 opt)
sd->bonus.short_attack_atk_rate += 5 * sc->getSCE( SC_RUSH_QUAKE2 )->val1;
sd->bonus.long_attack_atk_rate += 5 * sc->getSCE( SC_RUSH_QUAKE2 )->val1;
}
if (sc->getSCE(SC_HIDDEN_CARD))
sd->bonus.long_attack_atk_rate += sc->getSCE(SC_HIDDEN_CARD)->val3;
if (sc->getSCE(SC_DEADLY_DEFEASANCE))
sd->special_state.no_magic_damage = 0;
if (sc->getSCE(SC_CLIMAX_DES_HU))
@ -7070,6 +7078,8 @@ static unsigned short status_calc_batk(struct block_list *bl, status_change *sc,
batk += 20;
if(sc->getSCE(SC_SKF_ATK))
batk += sc->getSCE(SC_SKF_ATK)->val1;
if (sc->getSCE(SC_INTENSIVE_AIM))
batk += 150;
return (unsigned short)cap_value(batk,0,USHRT_MAX);
}
@ -7386,6 +7396,8 @@ static signed short status_calc_critical(struct block_list *bl, status_change *s
critical += sc->getSCE(SC_MTF_HITFLEE)->val1;
if (sc->getSCE(SC_PACKING_ENVELOPE9))
critical += sc->getSCE(SC_PACKING_ENVELOPE9)->val1 * 10;
if (sc->getSCE(SC_INTENSIVE_AIM))
critical += 300;
return (short)cap_value(critical,10,SHRT_MAX);
}
@ -7462,6 +7474,8 @@ static signed short status_calc_hit(struct block_list *bl, status_change *sc, in
hit += sc->getSCE(SC_LIMIT_POWER_BOOSTER)->val1;
if (sc->getSCE(SC_ACARAJE))
hit += 5;
if (sc->getSCE(SC_INTENSIVE_AIM))
hit += 250;
return (short)cap_value(hit,1,SHRT_MAX);
}
@ -8518,6 +8532,8 @@ static signed short status_calc_patk(struct block_list *bl, status_change *sc, i
if( sc->getSCE( SC_ATTACK_STANCE ) ){
patk += sc->getSCE( SC_ATTACK_STANCE )->val3;
}
if (sc->getSCE(SC_HIDDEN_CARD))
patk += sc->getSCE(SC_HIDDEN_CARD)->val2;
return (short)cap_value(patk, 0, SHRT_MAX);
}
@ -12741,6 +12757,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_WEAPONBREAKER:
val2 = val1 * 2 * 100; // Chance to break weapon
break;
case SC_INTENSIVE_AIM:
tick = 500;
break;
case SC_HIDDEN_CARD:
val2 = 3 * val1;
val3 = 10 * val1;
break;
default:
if (calc_flag.none() && scdb->skill_id == 0 && scdb->icon == EFST_BLANK && scdb->opt1 == OPT1_NONE && scdb->opt2 == OPT2_NONE && scdb->state.none() && scdb->flag.none() && scdb->endonstart.empty() && scdb->endreturn.empty() && scdb->fail.empty() && scdb->endonend.empty()) {
@ -14891,6 +14914,15 @@ TIMER_FUNC(status_change_timer){
if (sce->val4 >= 0)
skill_castend_damage_id( bl, bl, NPC_KILLING_AURA, sce->val1, tick, 0 );
break;
case SC_INTENSIVE_AIM:
if (!sc || !sc->getSCE(SC_INTENSIVE_AIM_COUNT))
sce->val4 = 0;
if (sce->val4 < 10) {
sce->val4++;
sc_start(bl, bl, SC_INTENSIVE_AIM_COUNT, 100, sce->val4, INFINITE_TICK);
}
sc_timer_next(500 + tick);
return 0;
}
// If status has an interval and there is at least 100ms remaining time, wait for next interval

View File

@ -1293,6 +1293,18 @@ enum sc_type : int16 {
SC_BREAKINGLIMIT,
SC_RULEBREAK,
// Night Watch
SC_INTENSIVE_AIM,
SC_INTENSIVE_AIM_COUNT,
SC_GRENADE_FRAGMENT_1,
SC_GRENADE_FRAGMENT_2,
SC_GRENADE_FRAGMENT_3,
SC_GRENADE_FRAGMENT_4,
SC_GRENADE_FRAGMENT_5,
SC_GRENADE_FRAGMENT_6,
SC_AUTO_FIRING_LAUNCHER,
SC_HIDDEN_CARD,
#ifdef RENEWAL
SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled
#endif