* INF2_NO_NEARNPC (skill_db.txt updates):
-- Added a new option info for skill's 'inf2', INF2_NO_NEARNPC, that used for checking if the skill is castable if caster/ground/target is near with NPC (by specified range option) -- Corrected Shadow Chaser skills, SC_CHAOSPANIC and SC_MAELSTROM, that cannot be placed near warp portal (according to iRO Skill Balance Patch) -- Added 'db/skill_nonearnpc_db.txt' for more option of INF2_NO_NEARNPC (additional range beside splash area, unit range, or layout range calculaiton and type of NPC) * Follow up 5e6626e
This commit is contained in:
parent
99ea656914
commit
659cc57574
@ -23,27 +23,30 @@
|
||||
// 10 Cast interrupted when hit?
|
||||
// 11 defense-reduction rate during cast.
|
||||
// 12 inf2 (skill information 2):
|
||||
// 0x0001- quest skill
|
||||
// 0x0002- npc skill
|
||||
// 0x0004- wedding skill
|
||||
// 0x0008- spirit skill
|
||||
// 0x0010- guild skill
|
||||
// 0x0020- song/dance
|
||||
// 0x0040- ensemble skill
|
||||
// 0x0080- trap
|
||||
// 0x0100- skill that damages/targets yourself
|
||||
// 0x0200- cannot be casted on self (if inf = 4, auto-select target skill)
|
||||
// 0x0400- usable only on party-members (and enemies if skill is offensive)
|
||||
// 0x0800- usable only on guild-mates (and enemies if skill is offensive)
|
||||
// 0x1000- disable usage on enemies (for non-offensive skills).
|
||||
// 0x2000- free
|
||||
// 0x4000- chorus skill
|
||||
// 0x00001- quest skill
|
||||
// 0x00002- npc skill
|
||||
// 0x00004- wedding skill
|
||||
// 0x00008- spirit skill
|
||||
// 0x00010- guild skill
|
||||
// 0x00020- song/dance
|
||||
// 0x00040- ensemble skill
|
||||
// 0x00080- trap
|
||||
// 0x00100- skill that damages/targets yourself
|
||||
// 0x00200- cannot be casted on self (if inf = 4, auto-select target skill)
|
||||
// 0x00400- usable only on party-members (and enemies if skill is offensive)
|
||||
// 0x00800- usable only on guild-mates (and enemies if skill is offensive)
|
||||
// 0x01000- disable usage on enemies (for non-offensive skills).
|
||||
// 0x02000- free
|
||||
// 0x04000- chorus skill
|
||||
// 0x08000- spell that ignore bg reduction
|
||||
// 0x10000- spell that ignore gvg reduction
|
||||
// 0x20000- makes 'self'/'place' skill cannot be casted/placed when near NPC (see 'db/skill_nonearnpc_db.txt' for more options)
|
||||
// 13 maxcount: max amount of skill instances to place on the ground when
|
||||
// player_land_skill_limit/monster_land_skill_limit is enabled. For skills
|
||||
// that attack using a path, this is the path length to be used.
|
||||
// 14 attack type (none, weapon, magic, misc)
|
||||
// 15 Blowcount (amount of tiles skill knockbacks)
|
||||
// 16 inf3 (skill option)
|
||||
// 16 inf3 (skill information 3):
|
||||
// 0x0001- skill ignores land protector (e.g. arrow shower)
|
||||
// 0x0002- spell that doesn't end camouflage
|
||||
// 0x0004- usable skills while hiding
|
||||
@ -1036,8 +1039,8 @@
|
||||
2298,3,6,1,0,0x1,0,5,1,yes,0,0,0,weapon,0,0x20, SC_STRIPACCESSARY,Strip Accessory //CHECK Is weapon attack type needed?
|
||||
2299,7,6,2,0,0x1,0,3,1,yes,0,0,3,none,0,0x0, SC_MANHOLE,Man Hole
|
||||
2300,7,6,2,0,0x1,0,3,1,yes,0,0,1,none,0,0x0, SC_DIMENSIONDOOR,Dimension Door
|
||||
2301,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0, SC_CHAOSPANIC,Chaos Panic
|
||||
2302,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0, SC_MAELSTROM,Maelstrom
|
||||
2301,7,6,2,0,0x1,0,3,1,yes,0,0x20000,0,none,0,0x0, SC_CHAOSPANIC,Chaos Panic
|
||||
2302,7,6,2,0,0x1,0,3,1,yes,0,0x20000,0,none,0,0x0, SC_MAELSTROM,Maelstrom
|
||||
2303,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0, SC_BLOODYLUST,Bloody Lust
|
||||
2304,0,6,4,-1,0,0,3,1,no,0,0,0,weapon,0,0x0, SC_FEINTBOMB,Feint Bomb
|
||||
|
||||
|
@ -3,19 +3,19 @@
|
||||
// layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11
|
||||
// target = friend (party +guildmates +neutral players) / party / guild
|
||||
// ally (party +guildmates) / all / enemy
|
||||
// flag 0x001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend'
|
||||
// 0x002(UF_NOREITERRATION) Spell cannot be stacked
|
||||
// 0x004(UF_NOFOOTSET) Spell cannot be cast near/on targets
|
||||
// 0x008(UF_NOOVERLAP) Spell effects do not overlap
|
||||
// 0x010(UF_PATHCHECK) Only cells with a shootable path will be placed
|
||||
// 0x020(UF_NOPC) Spell cannot affect players.
|
||||
// 0x040(UF_NOMOB) Spell cannot affect mobs.
|
||||
// 0x080(UF_SKILL) Spell CAN affect skills.
|
||||
// 0x100(UF_DANCE) Dance skill
|
||||
// 0x200(UF_ENSEMBLE) Ensemble skill
|
||||
// 0x400(UF_SONG) Song skill
|
||||
// 0x800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out
|
||||
// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center.
|
||||
// flag 0x0001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend'
|
||||
// 0x0002(UF_NOREITERRATION) Spell cannot be stacked
|
||||
// 0x0004(UF_NOFOOTSET) Spell cannot be cast near/on targets
|
||||
// 0x0008(UF_NOOVERLAP) Spell effects do not overlap
|
||||
// 0x0010(UF_PATHCHECK) Only cells with a shootable path will be placed
|
||||
// 0x0020(UF_NOPC) Spell cannot affect players.
|
||||
// 0x0040(UF_NOMOB) Spell cannot affect mobs.
|
||||
// 0x0080(UF_SKILL) Spell CAN affect skills.
|
||||
// 0x0100(UF_DANCE) Dance skill
|
||||
// 0x0200(UF_ENSEMBLE) Ensemble skill
|
||||
// 0x0400(UF_SONG) Song skill
|
||||
// 0x0800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out
|
||||
// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center.
|
||||
// Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets
|
||||
//
|
||||
// Notes:
|
||||
|
@ -40,6 +40,7 @@
|
||||
// 0x04000- chorus skill
|
||||
// 0x08000- spell that ignore bg reduction
|
||||
// 0x10000- spell that ignore gvg reduction
|
||||
// 0x20000- makes 'self'/'place' skill cannot be casted/placed when near NPC (see 'db/skill_nonearnpc_db.txt' for more options)
|
||||
// 13 maxcount: max amount of skill instances to place on the ground when
|
||||
// player_land_skill_limit/monster_land_skill_limit is enabled. For skills
|
||||
// that attack using a path, this is the path length to be used.
|
||||
@ -1049,8 +1050,8 @@
|
||||
2298,3,6,1,0,0x1,0,5,1,yes,0,0,0,weapon,0,0x20, SC_STRIPACCESSARY,Strip Accessory //CHECK Is weapon attack type needed?
|
||||
2299,7,6,2,0,0x1,0,3,1,yes,0,0,3,none,0,0x0, SC_MANHOLE,Man Hole
|
||||
2300,7,6,2,0,0x1,0,3,1,yes,0,0,1,none,0,0x0, SC_DIMENSIONDOOR,Dimension Door
|
||||
2301,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0, SC_CHAOSPANIC,Chaos Panic
|
||||
2302,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0,0x0, SC_MAELSTROM,Maelstrom
|
||||
2301,7,6,2,0,0x1,0,3,1,yes,0,0x20000,0,none,0,0x0, SC_CHAOSPANIC,Chaos Panic
|
||||
2302,7,6,2,0,0x1,0,3,1,yes,0,0x20000,0,none,0,0x0, SC_MAELSTROM,Maelstrom
|
||||
2303,7,6,2,0,0x1,3,3,1,yes,0,0,1,none,0,0x0, SC_BLOODYLUST,Bloody Lust
|
||||
2304,0,6,4,-1,0,0,3,1,no,0,0,0,weapon,0,0x0, SC_FEINTBOMB,Feint Bomb
|
||||
|
||||
|
@ -3,19 +3,19 @@
|
||||
// layout = -1:special, 0:1*1, 1:3*3, 2:5*5, up to 5:11*11
|
||||
// target = friend (party +guildmates +neutral players) / party / guild
|
||||
// ally (party +guildmates) / all / enemy
|
||||
// flag 0x001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend'
|
||||
// 0x002(UF_NOREITERRATION) Spell cannot be stacked
|
||||
// 0x004(UF_NOFOOTSET) Spell cannot be cast near/on targets
|
||||
// 0x008(UF_NOOVERLAP) Spell effects do not overlap
|
||||
// 0x010(UF_PATHCHECK) Only cells with a shootable path will be placed
|
||||
// 0x020(UF_NOPC) Spell cannot affect players.
|
||||
// 0x040(UF_NOMOB) Spell cannot affect mobs.
|
||||
// 0x080(UF_SKILL) Spell CAN affect skills.
|
||||
// 0x100(UF_DANCE) Dance skill
|
||||
// 0x200(UF_ENSEMBLE) Ensemble skill
|
||||
// 0x400(UF_SONG) Song skill
|
||||
// 0x800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out
|
||||
// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center.
|
||||
// flag 0x0001(UF_DEFNOTENEMY) If 'defunit_not_enemy' is set, the target is changed to 'friend'
|
||||
// 0x0002(UF_NOREITERRATION) Spell cannot be stacked
|
||||
// 0x0004(UF_NOFOOTSET) Spell cannot be cast near/on targets
|
||||
// 0x0008(UF_NOOVERLAP) Spell effects do not overlap
|
||||
// 0x0010(UF_PATHCHECK) Only cells with a shootable path will be placed
|
||||
// 0x0020(UF_NOPC) Spell cannot affect players.
|
||||
// 0x0040(UF_NOMOB) Spell cannot affect mobs.
|
||||
// 0x0080(UF_SKILL) Spell CAN affect skills.
|
||||
// 0x0100(UF_DANCE) Dance skill
|
||||
// 0x0200(UF_ENSEMBLE) Ensemble skill
|
||||
// 0x0400(UF_SONG) Song skill
|
||||
// 0x0800(UF_DUALMODE) Spell has effects both at an interval and when you step in/out
|
||||
// 0x2000(UF_RANGEDSINGLEUNIT) Layout hack, use layout range propriety but only display center.
|
||||
// Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets
|
||||
//
|
||||
// Notes:
|
||||
|
24
db/skill_nonearnpc_db.txt
Normal file
24
db/skill_nonearnpc_db.txt
Normal file
@ -0,0 +1,24 @@
|
||||
// Database of Additional Range and NPC Type that used by INF2_NO_NEARNPC
|
||||
// <skill_name>,<additional_range>{,<npc_type>}
|
||||
// ====================================================
|
||||
// additional_range: If this value is 0, splash range value will be used from skill_db,
|
||||
// or if it is 0, range+layout's range from skill_unit_db. Otherwise, the range
|
||||
// will be added.
|
||||
// npc_type (bitmask): 1 = warp portal, 2 = shop NPC, 4 = normal NPC script, 8 = tomb
|
||||
// ====================================================
|
||||
// Example:
|
||||
//MG_SAFETYWALL,2
|
||||
// MG_SAFETYWALL can't be placed if the ground's target is near from NPC by 2 cells
|
||||
// (MG_SAFETYWALL doesn't have splash, layout range, and range value, so must add the
|
||||
// 'additional_range', or it will be pointless)
|
||||
//
|
||||
//GS_DESPERADO,2
|
||||
// GS_DESPERADO can't be casted if the caster is standing near from NPC within range
|
||||
// 5 cells. (Why? GS_DESPERADO has 3 cells of splash range +2 'additional_range' here)
|
||||
//
|
||||
//SC_CHAOSPANIC,0,1
|
||||
// SC_CHAOSPANIC can't be placed on the ground that near the warp portal with range 2
|
||||
// cells. (Because SC_CHAOSPANIC doens't have splash range, it uses layout range)
|
||||
|
||||
SC_CHAOSPANIC,0,1
|
||||
SC_MAELSTROM,0,1
|
@ -10783,7 +10783,7 @@ static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_sess
|
||||
|
||||
if( !hd )
|
||||
return;
|
||||
if( skillnotok_hom(skill_id, hd) )
|
||||
if( skill_isNotOk_hom(skill_id, hd) )
|
||||
return;
|
||||
if( hd->bl.id != target_id && skill_get_inf(skill_id)&INF_SELF_SKILL )
|
||||
target_id = hd->bl.id;
|
||||
@ -10806,7 +10806,7 @@ static void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_ses
|
||||
int lv;
|
||||
if( !hd )
|
||||
return;
|
||||
if( skillnotok_hom(skill_id, hd) )
|
||||
if( skill_isNotOk_hom(skill_id, hd) )
|
||||
return;
|
||||
if( hd->ud.skilltimer != INVALID_TIMER ) {
|
||||
if( skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST ) return;
|
||||
@ -10828,7 +10828,7 @@ static void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct
|
||||
|
||||
if( !md )
|
||||
return;
|
||||
if( skillnotok_mercenary(skill_id, md) )
|
||||
if( skill_isNotOk_mercenary(skill_id, md) )
|
||||
return;
|
||||
if( md->bl.id != target_id && skill_get_inf(skill_id)&INF_SELF_SKILL )
|
||||
target_id = md->bl.id;
|
||||
@ -10851,7 +10851,7 @@ static void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct
|
||||
int lv;
|
||||
if( !md )
|
||||
return;
|
||||
if( skillnotok_mercenary(skill_id, md) )
|
||||
if( skill_isNotOk_mercenary(skill_id, md) )
|
||||
return;
|
||||
if( md->ud.skilltimer != INVALID_TIMER )
|
||||
return;
|
||||
@ -10920,7 +10920,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
|
||||
if( pc_issit(sd) )
|
||||
return;
|
||||
|
||||
if( skillnotok(skill_id, sd) )
|
||||
if( skill_isNotOk(skill_id, sd) )
|
||||
return;
|
||||
|
||||
if( sd->bl.id != target_id && tmp&INF_SELF_SKILL )
|
||||
@ -11002,7 +11002,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
|
||||
//Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex]
|
||||
sd->idletime = last_tick;
|
||||
|
||||
if( skillnotok(skill_id, sd) )
|
||||
if( skill_isNotOk(skill_id, sd) )
|
||||
return;
|
||||
if( skillmoreinfo != -1 ) {
|
||||
if( pc_issit(sd) ) {
|
||||
|
@ -562,7 +562,7 @@ int elemental_skillnotok(uint16 skill_id, struct elemental_data *ed) {
|
||||
if (idx == 0)
|
||||
return 1; // invalid skill id
|
||||
|
||||
return skillnotok(skill_id, ed->master);
|
||||
return skill_isNotOk(skill_id,ed->master);
|
||||
}
|
||||
|
||||
struct skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16 skill_lv){
|
||||
|
@ -118,8 +118,21 @@ struct view_data* npc_get_viewdata(int class_)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int npc_isnear_sub(struct block_list* bl, va_list args) {
|
||||
int npc_isnear_sub(struct block_list* bl, va_list args) {
|
||||
struct npc_data *nd = (struct npc_data*)bl;
|
||||
int skill_id = va_arg(args, int);
|
||||
uint16 idx = -1;
|
||||
|
||||
//Check the NPC type if is used by INF2_NO_NEARNPC or UF_NONEARNPC [Cydh]
|
||||
if (skill_id && (idx = skill_get_index(skill_id)) && skill_db[idx].unit_nonearnpc_type) {
|
||||
while (1) {
|
||||
if (skill_db[idx].unit_nonearnpc_type&1 && nd->subtype == WARP) break;
|
||||
if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == SHOP) break;
|
||||
if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == SCRIPT) break;
|
||||
if (skill_db[idx].unit_nonearnpc_type&8 && nd->subtype == TOMB) break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( nd->sc.option & (OPTION_HIDE|OPTION_INVISIBLE) )
|
||||
return 0;
|
||||
@ -130,7 +143,7 @@ static int npc_isnear_sub(struct block_list* bl, va_list args) {
|
||||
bool npc_isnear(struct block_list * bl) {
|
||||
|
||||
if( battle_config.min_npc_vendchat_distance > 0 &&
|
||||
map_foreachinrange(npc_isnear_sub,bl, battle_config.min_npc_vendchat_distance, BL_NPC) )
|
||||
map_foreachinrange(npc_isnear_sub,bl, battle_config.min_npc_vendchat_distance, BL_NPC, 0) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -136,6 +136,7 @@ int npc_enable(const char* name, int flag);
|
||||
void npc_setdisplayname(struct npc_data* nd, const char* newname);
|
||||
void npc_setclass(struct npc_data* nd, short class_);
|
||||
struct npc_data* npc_name2id(const char* name);
|
||||
int npc_isnear_sub(struct block_list* bl, va_list args);
|
||||
bool npc_isnear(struct block_list * bl);
|
||||
|
||||
int npc_get_new_npc_id(void);
|
||||
|
332
src/map/skill.c
332
src/map/skill.c
@ -121,7 +121,7 @@ int earthstrain_unit_pos;
|
||||
//early declaration
|
||||
int skill_block_check(struct block_list *bl, enum sc_type type, uint16 skill_id);
|
||||
static int skill_check_unit_range (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv);
|
||||
static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv);
|
||||
static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv, bool isNearNPC);
|
||||
static int skill_destroy_trap( struct block_list *bl, va_list ap );
|
||||
static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list ap);
|
||||
//Since only mob-casted splash skills can hit ice-walls
|
||||
@ -483,42 +483,43 @@ static short skill_isCopyable (struct map_session_data *sd, uint16 skill_id, str
|
||||
|
||||
// [MouseJstr] - skill ok to cast? and when?
|
||||
//done before check_condition_begin, requirement
|
||||
int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
|
||||
{
|
||||
int16 idx,m;
|
||||
nullpo_retr (1, sd);
|
||||
nullpo_retr(1,sd);
|
||||
m = sd->bl.m;
|
||||
idx = skill_get_index(skill_id);
|
||||
|
||||
if (idx == 0)
|
||||
return 1; // invalid skill id
|
||||
return true; // invalid skill id
|
||||
|
||||
if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL))
|
||||
return 0; // can do any damn thing they want
|
||||
if (pc_has_permission(sd,PC_PERM_SKILL_UNCONDITIONAL))
|
||||
return false; // can do any damn thing they want
|
||||
|
||||
if( skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2 )
|
||||
return 0; // Teleport lv 3 bypasses this check.[Inkfish]
|
||||
if (skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2)
|
||||
return false; // Teleport lv 3 bypasses this check.[Inkfish]
|
||||
|
||||
// Epoque:
|
||||
// This code will compare the player's attack motion value which is influenced by ASPD before
|
||||
// allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as
|
||||
// AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion.
|
||||
if( !sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick &&
|
||||
DIFF_TICK(gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) )
|
||||
if (!sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick &&
|
||||
DIFF_TICK(gettick(),sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100))
|
||||
{// attempted to cast a skill before the attack motion has finished
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sd->blockskill[idx] > 0){
|
||||
clif_skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0);
|
||||
return 1;
|
||||
if (sd->blockskill[idx] > 0) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* It has been confirmed on a official server (thanks to Yommy) that item-cast skills bypass all the restrictions above
|
||||
* Also, without this check, an exploit where an item casting + healing (or any other kind buff) isn't deleted after used on a restricted map
|
||||
**/
|
||||
if( sd->skillitem == skill_id )
|
||||
return 0;
|
||||
return false;
|
||||
// Check skill restrictions [Celest]
|
||||
if( (!map_flag_vs(m) && skill_get_nocast (skill_id) & 1) ||
|
||||
(map[m].flag.pvp && skill_get_nocast (skill_id) & 2) ||
|
||||
@ -526,11 +527,11 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
(map[m].flag.battleground && skill_get_nocast (skill_id) & 8) ||
|
||||
(map[m].flag.restricted && map[m].zone && skill_get_nocast (skill_id) & (8*map[m].zone)) ){
|
||||
clif_msg(sd, 0x536); // This skill cannot be used within this area
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( sd->sc.option&OPTION_MOUNTING )
|
||||
return 1;//You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
|
||||
return true;//You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
|
||||
|
||||
switch (skill_id) {
|
||||
case AL_WARP:
|
||||
@ -539,24 +540,24 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
case ECLAGE_RECALL:
|
||||
if(map[m].flag.nowarp) {
|
||||
clif_skill_teleportmessage(sd,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
case AL_TELEPORT:
|
||||
case SC_FATALMENACE:
|
||||
case SC_DIMENSIONDOOR:
|
||||
case ALL_ODINS_RECALL:
|
||||
if(map[m].flag.noteleport) {
|
||||
clif_skill_teleportmessage(sd,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0; // gonna be checked in 'skill_castend_nodamage_id'
|
||||
return false; // gonna be checked in 'skill_castend_nodamage_id'
|
||||
case WE_CALLPARTNER:
|
||||
case WE_CALLPARENT:
|
||||
case WE_CALLBABY:
|
||||
if (map[m].flag.nomemo) {
|
||||
clif_skill_teleportmessage(sd,1);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MC_VENDING:
|
||||
@ -564,12 +565,12 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
if( map[sd->bl.m].flag.novending ) {
|
||||
clif_displaymessage (sd->fd, msg_txt(sd,276)); // "You can't open a shop on this map"
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
if( map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) {
|
||||
clif_displaymessage (sd->fd, msg_txt(sd,204)); // "You can't open a shop on this cell."
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
if( npc_isnear(&sd->bl) ) {
|
||||
// uncomment to send msg_txt.
|
||||
@ -577,21 +578,21 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
//sprintf(output, msg_txt(662), battle_config.min_npc_vendchat_distance);
|
||||
//clif_displaymessage(sd->fd, output);
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_THERE_ARE_NPC_AROUND,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
case MC_IDENTIFY:
|
||||
return 0; // always allowed
|
||||
return false; // always allowed
|
||||
case WZ_ICEWALL:
|
||||
// noicewall flag [Valaris]
|
||||
if (map[m].flag.noicewall) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case GC_DARKILLUSION:
|
||||
if( map_flag_gvg(m) ) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case GD_EMERGENCYCALL:
|
||||
@ -602,7 +603,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
(battle_config.emergency_call&16 && map[m].flag.nowarpto && !map[m].flag.gvg_castle)
|
||||
) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case BS_GREED:
|
||||
@ -619,7 +620,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
**/
|
||||
if( pc_ismadogear(sd) ) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -630,7 +631,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
case WM_SATURDAY_NIGHT_FEVER:
|
||||
if( !map_flag_vs(m) ) {
|
||||
clif_skill_teleportmessage(sd,2); // This skill uses this msg instead of skill fails.
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -638,64 +639,91 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
|
||||
return (map[m].flag.noskill);
|
||||
}
|
||||
|
||||
int skillnotok_hom(uint16 skill_id, struct homun_data *hd)
|
||||
bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd)
|
||||
{
|
||||
uint16 idx = skill_get_index(skill_id);
|
||||
nullpo_retr(1,hd);
|
||||
|
||||
if (idx == 0)
|
||||
return 1; // invalid skill id
|
||||
return true; // invalid skill id
|
||||
|
||||
if (hd->blockskill[idx] > 0)
|
||||
return 1;
|
||||
switch(skill_id){
|
||||
case MH_LIGHT_OF_REGENE: //must be cordial
|
||||
if(hd->homunculus.intimacy <= 750) return 1;
|
||||
break;
|
||||
case MH_OVERED_BOOST: //if we starving
|
||||
if(hd->homunculus.hunger <= 1) return 1;
|
||||
break;
|
||||
case MH_GOLDENE_FERSE: //cant be used with angriff
|
||||
if(hd->sc.data[SC_ANGRIFFS_MODUS]) return 1;
|
||||
break;
|
||||
case MH_ANGRIFFS_MODUS:
|
||||
if(hd->sc.data[SC_GOLDENE_FERSE]) return 1;
|
||||
break;
|
||||
case MH_TINDER_BREAKER: //must be in grappling mode
|
||||
if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) return 1;
|
||||
break;
|
||||
case MH_SONIC_CRAW: //must be in fighting mode
|
||||
if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) return 1;
|
||||
break;
|
||||
case MH_SILVERVEIN_RUSH:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)) return 1;
|
||||
break;
|
||||
case MH_MIDNIGHT_FRENZY:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) return 1;
|
||||
break;
|
||||
case MH_CBC:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) return 1;
|
||||
break;
|
||||
case MH_EQC:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)) return 1;
|
||||
break;
|
||||
return true;
|
||||
|
||||
switch(skill_id) {
|
||||
case MH_LIGHT_OF_REGENE: //must be cordial
|
||||
if(hd->homunculus.intimacy <= 750) return true;
|
||||
break;
|
||||
case MH_OVERED_BOOST: //if we starving
|
||||
if(hd->homunculus.hunger <= 1) return true;
|
||||
break;
|
||||
case MH_GOLDENE_FERSE: //cant be used with angriff
|
||||
if(hd->sc.data[SC_ANGRIFFS_MODUS]) return true;
|
||||
break;
|
||||
case MH_ANGRIFFS_MODUS:
|
||||
if(hd->sc.data[SC_GOLDENE_FERSE]) return true;
|
||||
break;
|
||||
case MH_TINDER_BREAKER: //must be in grappling mode
|
||||
if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) return true;
|
||||
break;
|
||||
case MH_SONIC_CRAW: //must be in fighting mode
|
||||
if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) return true;
|
||||
break;
|
||||
case MH_SILVERVEIN_RUSH:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)) return true;
|
||||
break;
|
||||
case MH_MIDNIGHT_FRENZY:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) return true;
|
||||
break;
|
||||
case MH_CBC:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) return true;
|
||||
break;
|
||||
case MH_EQC:
|
||||
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
//Use master's criteria.
|
||||
return skillnotok(skill_id, hd->master);
|
||||
return skill_isNotOk(skill_id, hd->master);
|
||||
}
|
||||
|
||||
int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md)
|
||||
bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md)
|
||||
{
|
||||
uint16 idx = skill_get_index(skill_id);
|
||||
nullpo_retr(1,md);
|
||||
|
||||
if( idx == 0 )
|
||||
return 1; // Invalid Skill ID
|
||||
return true; // Invalid Skill ID
|
||||
if( md->blockskill[idx] > 0 )
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return skillnotok(skill_id, md->master);
|
||||
return skill_isNotOk(skill_id, md->master);
|
||||
}
|
||||
|
||||
/// Check if the skill can be casted near NPC or not [Cydh]
|
||||
/// NOTE: 'target' may be NULL if the skill is targetting ground/area
|
||||
bool skill_isNotOk_npcRange(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int pos_x, int pos_y) {
|
||||
int inf;
|
||||
|
||||
if (!src || skill_get_index(skill_id) < 0)
|
||||
return false;
|
||||
|
||||
if (src->type == BL_PC && pc_has_permission(BL_CAST(BL_PC,src),PC_PERM_SKILL_UNCONDITIONAL))
|
||||
return false;
|
||||
|
||||
inf = skill_get_inf(skill_id);
|
||||
//if self skill
|
||||
if (inf&INF_SELF_SKILL) {
|
||||
pos_x = src->x;
|
||||
pos_y = src->y;
|
||||
}
|
||||
|
||||
if (pos_x <= 0 || pos_y <= 0) {
|
||||
pos_x = src->x;
|
||||
pos_y = src->y;
|
||||
}
|
||||
|
||||
return skill_check_unit_range2(src,pos_x,pos_y,skill_id,skill_lv,true);
|
||||
}
|
||||
|
||||
struct s_skill_unit_layout* skill_get_unit_layout (uint16 skill_id, uint16 skill_lv, struct block_list* src, int x, int y) {
|
||||
@ -1524,7 +1552,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
|
||||
{
|
||||
struct block_list *tbl;
|
||||
struct unit_data *ud;
|
||||
int i, skill_lv, type, notok;
|
||||
int i, skill_lv, type;
|
||||
|
||||
for (i = 0; i < ARRAYLENGTH(sd->autospell) && sd->autospell[i].id; i++) {
|
||||
|
||||
@ -1536,15 +1564,14 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
|
||||
skill = (sd->autospell[i].id > 0) ? sd->autospell[i].id : -sd->autospell[i].id;
|
||||
|
||||
sd->state.autocast = 1;
|
||||
notok = skillnotok(skill, sd);
|
||||
sd->state.autocast = 0;
|
||||
|
||||
if ( notok )
|
||||
continue;
|
||||
|
||||
skill_lv = sd->autospell[i].lv?sd->autospell[i].lv:1;
|
||||
if (skill_lv < 0) skill_lv = 1+rnd()%(-skill_lv);
|
||||
|
||||
if ( skill_isNotOk(skill, sd) )
|
||||
continue;
|
||||
|
||||
rate = (!sd->state.arrow_atk) ? sd->autospell[i].rate : sd->autospell[i].rate / 2;
|
||||
|
||||
if (rnd()%1000 >= rate)
|
||||
@ -1557,15 +1584,13 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
|
||||
if( !(BL_PC&battle_config.skill_reiteration) &&
|
||||
skill_get_unit_flag(skill)&UF_NOREITERATION &&
|
||||
skill_check_unit_range(src,tbl->x,tbl->y,skill,skill_lv)
|
||||
) {
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.skill_nofootset &&
|
||||
skill_get_unit_flag(skill)&UF_NOFOOTSET &&
|
||||
skill_check_unit_range2(src,tbl->x,tbl->y,skill,skill_lv)
|
||||
) {
|
||||
skill_check_unit_range2(src,tbl->x,tbl->y,skill,skill_lv,false)
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.land_skill_limit &&
|
||||
(maxcount = skill_get_maxcount(skill, skill_lv)) > 0
|
||||
) {
|
||||
@ -1574,9 +1599,8 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
|
||||
if(sd->ud.skillunit[v]->skill_id == skill)
|
||||
maxcount--;
|
||||
}
|
||||
if( maxcount == 0 ) {
|
||||
if( maxcount == 0 )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( battle_config.autospell_check_range &&
|
||||
@ -1660,7 +1684,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
|
||||
}
|
||||
|
||||
int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint16 skill_id, unsigned int tick) {
|
||||
int skill, skill_lv, i, type, notok;
|
||||
int skill, skill_lv, i, type;
|
||||
struct block_list *tbl;
|
||||
|
||||
if( sd == NULL || !skill_id )
|
||||
@ -1676,12 +1700,11 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
|
||||
skill = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id;
|
||||
|
||||
sd->state.autocast = 1;
|
||||
notok = skillnotok(skill, sd);
|
||||
sd->state.autocast = 0;
|
||||
|
||||
if ( notok )
|
||||
if ( skill_isNotOk(skill, sd) )
|
||||
continue;
|
||||
|
||||
|
||||
skill_lv = sd->autospell3[i].lv ? sd->autospell3[i].lv : 1;
|
||||
if( skill_lv < 0 ) skill_lv = 1 + rnd()%(-skill_lv);
|
||||
|
||||
@ -1689,23 +1712,20 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
|
||||
continue; // No target
|
||||
if( rnd()%1000 >= sd->autospell3[i].rate )
|
||||
continue;
|
||||
|
||||
|
||||
tbl = (sd->autospell3[i].id < 0) ? &sd->bl : bl;
|
||||
|
||||
if( (type = skill_get_casttype(skill)) == CAST_GROUND ) {
|
||||
int maxcount = 0;
|
||||
if( !(BL_PC&battle_config.skill_reiteration) &&
|
||||
skill_get_unit_flag(skill)&UF_NOREITERATION &&
|
||||
skill_check_unit_range(&sd->bl,tbl->x,tbl->y,skill,skill_lv)
|
||||
) {
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.skill_nofootset &&
|
||||
skill_get_unit_flag(skill)&UF_NOFOOTSET &&
|
||||
skill_check_unit_range2(&sd->bl,tbl->x,tbl->y,skill,skill_lv)
|
||||
) {
|
||||
skill_check_unit_range2(&sd->bl,tbl->x,tbl->y,skill,skill_lv,false)
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.land_skill_limit &&
|
||||
(maxcount = skill_get_maxcount(skill, skill_lv)) > 0
|
||||
) {
|
||||
@ -1714,9 +1734,8 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
|
||||
if(sd->ud.skillunit[v]->skill_id == skill)
|
||||
maxcount--;
|
||||
}
|
||||
if( maxcount == 0 ) {
|
||||
if( maxcount == 0 )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( battle_config.autospell_check_range &&
|
||||
@ -1868,7 +1887,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
|
||||
{
|
||||
struct block_list *tbl;
|
||||
struct unit_data *ud;
|
||||
int i, skill_id, skill_lv, rate, type, notok;
|
||||
int i, skill_id, skill_lv, rate, type;
|
||||
|
||||
for (i = 0; i < ARRAYLENGTH(dstsd->autospell2) && dstsd->autospell2[i].id; i++) {
|
||||
|
||||
@ -1886,31 +1905,27 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
|
||||
rate>>=1;
|
||||
|
||||
dstsd->state.autocast = 1;
|
||||
notok = skillnotok(skill_id, dstsd);
|
||||
dstsd->state.autocast = 0;
|
||||
|
||||
if ( notok )
|
||||
if ( skill_isNotOk(skill_id, dstsd) )
|
||||
continue;
|
||||
|
||||
if (rnd()%1000 >= rate)
|
||||
continue;
|
||||
|
||||
tbl = (dstsd->autospell2[i].id < 0) ? bl : src;
|
||||
|
||||
if( (type = skill_get_casttype(skill_id)) == CAST_GROUND ) {
|
||||
int maxcount = 0;
|
||||
if( !(BL_PC&battle_config.skill_reiteration) &&
|
||||
skill_get_unit_flag(skill_id)&UF_NOREITERATION &&
|
||||
skill_check_unit_range(bl,tbl->x,tbl->y,skill_id,skill_lv)
|
||||
) {
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.skill_nofootset &&
|
||||
skill_get_unit_flag(skill_id)&UF_NOFOOTSET &&
|
||||
skill_check_unit_range2(bl,tbl->x,tbl->y,skill_id,skill_lv)
|
||||
) {
|
||||
skill_check_unit_range2(bl,tbl->x,tbl->y,skill_id,skill_lv,false)
|
||||
)
|
||||
continue;
|
||||
}
|
||||
if( BL_PC&battle_config.land_skill_limit &&
|
||||
(maxcount = skill_get_maxcount(skill_id, skill_lv)) > 0
|
||||
) {
|
||||
@ -3027,36 +3042,53 @@ static int skill_check_unit_range2_sub (struct block_list *bl, va_list ap)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv)
|
||||
//NOTE: 'isNearNPC' is used to check is the skill near NPC or not, if yes will use npc_isnear and range calculation [Cydh]
|
||||
static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv, bool isNearNPC)
|
||||
{
|
||||
int range, type;
|
||||
int range = 0, type;
|
||||
|
||||
switch (skill_id) { // to be expanded later
|
||||
case WZ_ICEWALL:
|
||||
range = 2;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int layout_type = skill_get_unit_layout_type(skill_id,skill_lv);
|
||||
if (layout_type==-1 || layout_type>MAX_SQUARE_LAYOUT) {
|
||||
ShowError("skill_check_unit_range2: unsupported layout type %d for skill %d\n",layout_type,skill_id);
|
||||
return 0;
|
||||
}
|
||||
range = skill_get_unit_range(skill_id,skill_lv) + layout_type;
|
||||
//Range for INF2_NO_NEARNPC is using skill splash value [Cydh]
|
||||
if (isNearNPC)
|
||||
range = skill_get_splash(skill_id,skill_lv);
|
||||
|
||||
//While checking INF2_NO_NEARNPC and the range from splash is 0, get the range from skill_unit range and layout. [Cydh]
|
||||
if (!isNearNPC || !range) {
|
||||
switch (skill_id) { // to be expanded later
|
||||
case WZ_ICEWALL:
|
||||
range = 2;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int layout_type = skill_get_unit_layout_type(skill_id,skill_lv);
|
||||
if (layout_type == -1 || layout_type > MAX_SQUARE_LAYOUT) {
|
||||
ShowError("skill_check_unit_range2: unsupported layout type %d for skill %d\n",layout_type,skill_id);
|
||||
return 0;
|
||||
}
|
||||
range = skill_get_unit_range(skill_id,skill_lv) + layout_type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// if the caster is a monster/NPC, only check for players
|
||||
// otherwise just check characters
|
||||
if (bl->type == BL_PC)
|
||||
type = BL_CHAR;
|
||||
else
|
||||
type = BL_PC;
|
||||
//Check the additional range [Cydh]
|
||||
if (isNearNPC && skill_db[skill_get_index(skill_id)].unit_nonearnpc_range)
|
||||
range += skill_db[skill_get_index(skill_id)].unit_nonearnpc_range;
|
||||
|
||||
return map_foreachinarea(skill_check_unit_range2_sub, bl->m,
|
||||
x - range, y - range, x + range, y + range,
|
||||
type, skill_id);
|
||||
if (!isNearNPC) { //Doesn't check the NPC range
|
||||
//If the caster is a monster/NPC, only check for players. Otherwise just check characters
|
||||
if (bl->type == BL_PC)
|
||||
type = BL_CHAR;
|
||||
else
|
||||
type = BL_PC;
|
||||
}
|
||||
else
|
||||
type = BL_NPC;
|
||||
|
||||
return (!isNearNPC) ?
|
||||
//!isNearNPC is used for UF_NOFOOTSET, regardless the NPC position, only check the BL_CHAR or BL_PC
|
||||
map_foreachinarea(skill_check_unit_range2_sub,bl->m,x - range,y - range,x + range,y + range,type,skill_id):
|
||||
//isNearNPC is used to check range from NPC
|
||||
map_foreachinarea(npc_isnear_sub,bl->m,x - range,y - range,x + range,y + range,type,skill_id);
|
||||
}
|
||||
|
||||
int skill_guildaura_sub (struct map_session_data* sd, int id, int strvit, int agidex)
|
||||
@ -9778,7 +9810,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data)
|
||||
}
|
||||
if( src->type&battle_config.skill_nofootset &&
|
||||
skill_get_unit_flag(ud->skill_id)&UF_NOFOOTSET &&
|
||||
skill_check_unit_range2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv)
|
||||
skill_check_unit_range2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv,false)
|
||||
)
|
||||
{
|
||||
if (sd) clif_skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
@ -13129,7 +13161,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
|
||||
}
|
||||
case GD_EMERGENCYCALL:
|
||||
case GD_ITEMEMERGENCYCALL:
|
||||
// other checks were already done in skillnotok()
|
||||
// other checks were already done in skill_isNotOk()
|
||||
if (!sd->status.guild_id || !sd->state.gmaster_flag)
|
||||
return 0;
|
||||
break;
|
||||
@ -18252,16 +18284,16 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skill_parse_row_reproducedb(char* split[], int column, int current) {
|
||||
static bool skill_parse_row_copyabledb(char* split[], int column, int current) {
|
||||
uint16 skill_id = skill_name2id(split[0]), idx;
|
||||
uint8 option;
|
||||
|
||||
if (!skill_get_index(skill_id)) {
|
||||
ShowError("skill_parse_row_reproducedb: Invalid skill %s\n",split[0]);
|
||||
ShowError("skill_parse_row_copyabledb: Invalid skill '%s'\n",split[0]);
|
||||
return false;
|
||||
}
|
||||
if (!(option = atoi(split[1]))) {
|
||||
ShowError("skill_parse_row_reproducedb: Invalid option %d\n",option);
|
||||
ShowError("skill_parse_row_copyabledb: Invalid option %d\n",option);
|
||||
return false;
|
||||
}
|
||||
idx = skill_get_index(skill_id);
|
||||
@ -18277,6 +18309,19 @@ static bool skill_parse_row_reproducedb(char* split[], int column, int current)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reads additional range [Cydh]
|
||||
static bool skill_parse_row_nonearnpcrangedb(char* split[], int column, int current) {
|
||||
uint16 skill_id = skill_name2id(split[0]), idx;
|
||||
if ((idx = skill_get_index(skill_id)) < 0) { // invalid skill id
|
||||
ShowError("skill_parse_row_nonearnpcrangedb: Invalid skill '%s'\n",split[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
skill_db[idx].unit_nonearnpc_range = max(atoi(split[1]),0);
|
||||
skill_db[idx].unit_nonearnpc_type = (atoi(split[2])) ? cap_value(atoi(split[2]),1,15) : 15;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool skill_parse_row_abradb(char* split[], int columns, int current)
|
||||
{// skill_id,DummyName,RatePerLvl
|
||||
@ -18387,9 +18432,9 @@ static void skill_readdb(void)
|
||||
sv_readdb(db_path, DBPATH"skill_db.txt" , ',', 18, 18, MAX_SKILL_DB, skill_parse_row_skilldb);
|
||||
sv_readdb(db_path, DBPATH"skill_require_db.txt" , ',', 33, 33, MAX_SKILL_DB, skill_parse_row_requiredb);
|
||||
#ifdef RENEWAL_CAST
|
||||
sv_readdb(db_path, "re/skill_cast_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill_parse_row_castdb);
|
||||
sv_readdb(db_path, "re/skill_cast_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill_parse_row_castdb);
|
||||
#else
|
||||
sv_readdb(db_path, "pre-re/skill_cast_db.txt" , ',', 7, 7, MAX_SKILL_DB, skill_parse_row_castdb);
|
||||
sv_readdb(db_path, "pre-re/skill_cast_db.txt" , ',', 7, 7, MAX_SKILL_DB, skill_parse_row_castdb);
|
||||
#endif
|
||||
sv_readdb(db_path, DBPATH"skill_castnodex_db.txt", ',', 2, 3, MAX_SKILL_DB, skill_parse_row_castnodexdb);
|
||||
sv_readdb(db_path, DBPATH"skill_unit_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill_parse_row_unitdb);
|
||||
@ -18397,18 +18442,19 @@ static void skill_readdb(void)
|
||||
sv_readdb(db_path, DBPATH"skill_nocast_db.txt" , ',', 2, 2, MAX_SKILL_DB, skill_parse_row_nocastdb);
|
||||
|
||||
skill_init_unit_layout();
|
||||
sv_readdb(db_path, "produce_db.txt" , ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb);
|
||||
sv_readdb(db_path, "create_arrow_db.txt" , ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill_parse_row_createarrowdb);
|
||||
sv_readdb(db_path, "abra_db.txt" , ',', 3, 3, MAX_SKILL_ABRA_DB, skill_parse_row_abradb);
|
||||
sv_readdb(db_path, "produce_db.txt" , ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb);
|
||||
sv_readdb(db_path, "create_arrow_db.txt" , ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill_parse_row_createarrowdb);
|
||||
sv_readdb(db_path, "abra_db.txt" , ',', 3, 3, MAX_SKILL_ABRA_DB, skill_parse_row_abradb);
|
||||
//Warlock
|
||||
sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb);
|
||||
sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb);
|
||||
//Guillotine Cross
|
||||
sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb);
|
||||
sv_readdb(db_path, "skill_copyable_db.txt", ',', 2, 4, MAX_SKILL_DB, skill_parse_row_reproducedb);
|
||||
sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb);
|
||||
sv_readdb(db_path, "skill_copyable_db.txt" , ',', 2, 4, MAX_SKILL_DB, skill_parse_row_copyabledb);
|
||||
sv_readdb(db_path, "skill_improvise_db.txt" , ',', 2, 2, MAX_SKILL_IMPROVISE_DB, skill_parse_row_improvisedb);
|
||||
sv_readdb(db_path, "skill_changematerial_db.txt" , ',', 4, 4+2*5, MAX_SKILL_PRODUCE_DB, skill_parse_row_changematerialdb);
|
||||
sv_readdb(db_path, "skill_changematerial_db.txt" , ',', 4, 4+2*5, MAX_SKILL_PRODUCE_DB, skill_parse_row_changematerialdb);
|
||||
sv_readdb(db_path, "skill_nonearnpc_db.txt" , ',', 2, 3, MAX_SKILL_DB, skill_parse_row_nonearnpcrangedb);
|
||||
#ifdef ADJUST_SKILL_DAMAGE
|
||||
sv_readdb(db_path, "skill_damage_db.txt" , ',', 4, 7, MAX_SKILL_DB, skill_parse_row_skilldamage);
|
||||
sv_readdb(db_path, "skill_damage_db.txt" , ',', 4, 7, MAX_SKILL_DB, skill_parse_row_skilldamage);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ enum e_skill_inf2 {
|
||||
INF2_CHORUS_SKILL = 0x04000, // Chorus skill
|
||||
INF2_NO_BG_DMG = 0x08000, // spell that ignore bg reduction
|
||||
INF2_NO_GVG_DMG = 0x10000, // spell that ignore gvg reduction
|
||||
INF2_NO_NEARNPC = 0x20000, // disable cast skill if near with NPC [Cydh]
|
||||
};
|
||||
|
||||
/// Skill info type 3
|
||||
@ -163,6 +164,8 @@ struct s_skill_db {
|
||||
int unit_interval;
|
||||
int unit_target;
|
||||
int unit_flag;
|
||||
uint8 unit_nonearnpc_range; //additional range for UF_NONEARNPC or INF2_NO_NEARNPC [Cydh]
|
||||
uint8 unit_nonearnpc_type; //type of NPC [Cydh]
|
||||
#ifdef ADJUST_SKILL_DAMAGE
|
||||
struct s_skill_damage damage;
|
||||
#endif
|
||||
@ -361,7 +364,6 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
|
||||
int skill_clear_unitgroup(struct block_list *src);
|
||||
int skill_clear_group(struct block_list *bl, int flag);
|
||||
void ext_skill_unit_onplace(struct skill_unit *src, struct block_list *bl, unsigned int tick);
|
||||
|
||||
int64 skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,int64 damage,unsigned int tick);
|
||||
|
||||
int skill_castfix( struct block_list *bl, uint16 skill_id, uint16 skill_lv);
|
||||
@ -408,9 +410,11 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce
|
||||
|
||||
// Abnormal status
|
||||
int skill_enchant_elemental_end(struct block_list *bl, int type);
|
||||
int skillnotok(uint16 skill_id, struct map_session_data *sd);
|
||||
int skillnotok_hom(uint16 skill_id, struct homun_data *hd);
|
||||
int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md);
|
||||
bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd);
|
||||
bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd);
|
||||
bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md);
|
||||
|
||||
bool skill_isNotOk_npcRange(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int pos_x, int pos_y);
|
||||
|
||||
int skill_chastle_mob_changetarget(struct block_list *bl,va_list ap);
|
||||
|
||||
|
348
src/map/unit.c
348
src/map/unit.c
@ -1100,7 +1100,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
|
||||
//temp: used to signal combo-skills right now.
|
||||
if (sc && sc->data[SC_COMBO] && (sc->data[SC_COMBO]->val1 == skill_id ||
|
||||
(sd?skill_check_condition_castbegin(sd,skill_id,skill_lv):0) )) {
|
||||
(sd?skill_check_condition_castbegin(sd,skill_id,skill_lv):0) ))
|
||||
{
|
||||
if (sc->data[SC_COMBO]->val2)
|
||||
target_id = sc->data[SC_COMBO]->val2;
|
||||
else
|
||||
@ -1109,8 +1110,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
if( skill_get_inf(skill_id)&INF_SELF_SKILL && skill_get_nk(skill_id)&NK_NO_DAMAGE )// exploit fix
|
||||
target_id = src->id;
|
||||
combo = 1;
|
||||
} else
|
||||
if ( target_id == src->id &&
|
||||
}
|
||||
else if ( target_id == src->id &&
|
||||
skill_get_inf(skill_id)&INF_SELF_SKILL &&
|
||||
skill_get_inf2(skill_id)&INF2_NO_TARGET_SELF )
|
||||
{
|
||||
@ -1120,53 +1121,51 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
|
||||
if (sd) {
|
||||
//Target_id checking.
|
||||
if(skillnotok(skill_id, sd)) // [MouseJstr]
|
||||
if(skill_isNotOk(skill_id, sd)) // [MouseJstr]
|
||||
return 0;
|
||||
|
||||
switch(skill_id)
|
||||
{ //Check for skills that auto-select target
|
||||
case MO_CHAINCOMBO:
|
||||
if (sc && sc->data[SC_BLADESTOP]){
|
||||
if ((target=map_id2bl(sc->data[SC_BLADESTOP]->val4)) == NULL)
|
||||
switch(skill_id) { //Check for skills that auto-select target
|
||||
case MO_CHAINCOMBO:
|
||||
if (sc && sc->data[SC_BLADESTOP]) {
|
||||
if ((target=map_id2bl(sc->data[SC_BLADESTOP]->val4)) == NULL)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WE_MALE:
|
||||
case WE_FEMALE:
|
||||
if (!sd->status.partner_id)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WE_MALE:
|
||||
case WE_FEMALE:
|
||||
if (!sd->status.partner_id)
|
||||
return 0;
|
||||
target = (struct block_list*)map_charid2sd(sd->status.partner_id);
|
||||
if (!target) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
target = (struct block_list*)map_charid2sd(sd->status.partner_id);
|
||||
if (!target) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (target)
|
||||
target_id = target->id;
|
||||
}
|
||||
else if (src->type==BL_HOM)
|
||||
switch(skill_id)
|
||||
{ //Homun-auto-target skills.
|
||||
case HLIF_HEAL:
|
||||
case HLIF_AVOID:
|
||||
case HAMI_DEFENCE:
|
||||
case HAMI_CASTLE:
|
||||
target = battle_get_master(src);
|
||||
if (!target) return 0;
|
||||
target_id = target->id;
|
||||
break;
|
||||
case MH_SONIC_CRAW:
|
||||
case MH_TINDER_BREAKER: {
|
||||
int skill_id2 = ((skill_id==MH_SONIC_CRAW)?MH_MIDNIGHT_FRENZY:MH_EQC);
|
||||
if(sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id2){ //it,s a combo
|
||||
target_id = sc->data[SC_COMBO]->val2;
|
||||
combo = 1;
|
||||
casttime = -1;
|
||||
switch(skill_id) { //Homun-auto-target skills.
|
||||
case HLIF_HEAL:
|
||||
case HLIF_AVOID:
|
||||
case HAMI_DEFENCE:
|
||||
case HAMI_CASTLE:
|
||||
target = battle_get_master(src);
|
||||
if (!target) return 0;
|
||||
target_id = target->id;
|
||||
break;
|
||||
case MH_SONIC_CRAW:
|
||||
case MH_TINDER_BREAKER: {
|
||||
int skill_id2 = ((skill_id==MH_SONIC_CRAW)?MH_MIDNIGHT_FRENZY:MH_EQC);
|
||||
if(sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id2){ //it,s a combo
|
||||
target_id = sc->data[SC_COMBO]->val2;
|
||||
combo = 1;
|
||||
casttime = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !target ) // choose default target
|
||||
target = map_id2bl(target_id);
|
||||
@ -1187,44 +1186,50 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
if(!status_check_skilluse(src, target, skill_id, 0))
|
||||
return 0;
|
||||
|
||||
//fail if the targetted skill is near NPC [Cydh]
|
||||
if(skill_get_inf2(skill_id)&INF2_NO_NEARNPC && skill_isNotOk_npcRange(src,target,skill_id,skill_lv,target->x,target->y)) {
|
||||
if (sd)
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tstatus = status_get_status_data(target);
|
||||
// Record the status of the previous skill)
|
||||
if(sd) {
|
||||
switch(skill_id){
|
||||
case SA_CASTCANCEL:
|
||||
if(ud->skill_id != skill_id){
|
||||
sd->skill_id_old = ud->skill_id;
|
||||
sd->skill_lv_old = ud->skill_lv;
|
||||
}
|
||||
break;
|
||||
case BD_ENCORE:
|
||||
//Prevent using the dance skill if you no longer have the skill in your tree.
|
||||
if(!sd->skill_id_dance || pc_checkskill(sd,sd->skill_id_dance)<=0){
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
sd->skill_id_old = skill_id;
|
||||
break;
|
||||
case WL_WHITEIMPRISON:
|
||||
if( battle_check_target(src,target,BCT_SELF|BCT_ENEMY) < 0 ) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case MG_FIREBOLT:
|
||||
case MG_LIGHTNINGBOLT:
|
||||
case MG_COLDBOLT:
|
||||
sd->skill_id_old = skill_id;
|
||||
sd->skill_lv_old = skill_lv;
|
||||
break;
|
||||
switch(skill_id) {
|
||||
case SA_CASTCANCEL:
|
||||
if(ud->skill_id != skill_id) {
|
||||
sd->skill_id_old = ud->skill_id;
|
||||
sd->skill_lv_old = ud->skill_lv;
|
||||
}
|
||||
break;
|
||||
case BD_ENCORE:
|
||||
//Prevent using the dance skill if you no longer have the skill in your tree.
|
||||
if(!sd->skill_id_dance || pc_checkskill(sd,sd->skill_id_dance)<=0) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
sd->skill_id_old = skill_id;
|
||||
break;
|
||||
case WL_WHITEIMPRISON:
|
||||
if( battle_check_target(src,target,BCT_SELF|BCT_ENEMY) < 0 ) {
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case MG_FIREBOLT:
|
||||
case MG_LIGHTNINGBOLT:
|
||||
case MG_COLDBOLT:
|
||||
sd->skill_id_old = skill_id;
|
||||
sd->skill_lv_old = skill_lv;
|
||||
break;
|
||||
}
|
||||
if (!skill_check_condition_castbegin(sd, skill_id, skill_lv))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( src->type == BL_MOB )
|
||||
switch( skill_id )
|
||||
{
|
||||
switch( skill_id ) {
|
||||
case NPC_SUMMONSLAVE:
|
||||
case NPC_SUMMONMONSTER:
|
||||
case AL_TELEPORT:
|
||||
@ -1261,79 +1266,79 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
//temp: Used to signal force cast now.
|
||||
combo = 0;
|
||||
|
||||
switch(skill_id){
|
||||
case ALL_RESURRECTION:
|
||||
if(battle_check_undead(tstatus->race,tstatus->def_ele)) {
|
||||
combo = 1;
|
||||
} else if (!status_isdead(target))
|
||||
return 0; //Can't cast on non-dead characters.
|
||||
break;
|
||||
case MO_FINGEROFFENSIVE:
|
||||
if(sd)
|
||||
casttime += casttime * min(skill_lv, sd->spiritball);
|
||||
break;
|
||||
case MO_EXTREMITYFIST:
|
||||
if (sc && sc->data[SC_COMBO] &&
|
||||
(sc->data[SC_COMBO]->val1 == MO_COMBOFINISH ||
|
||||
sc->data[SC_COMBO]->val1 == CH_TIGERFIST ||
|
||||
sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH))
|
||||
casttime = -1;
|
||||
combo = 1;
|
||||
break;
|
||||
case SR_GATEOFHELL:
|
||||
case SR_TIGERCANNON:
|
||||
if (sc && sc->data[SC_COMBO] &&
|
||||
sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE)
|
||||
casttime = -1;
|
||||
combo = 1;
|
||||
break;
|
||||
case SA_SPELLBREAKER:
|
||||
combo = 1;
|
||||
break;
|
||||
case ST_CHASEWALK:
|
||||
if (sc && sc->data[SC_CHASEWALK])
|
||||
casttime = -1;
|
||||
break;
|
||||
case TK_RUN:
|
||||
if (sc && sc->data[SC_RUN])
|
||||
casttime = -1;
|
||||
break;
|
||||
case HP_BASILICA:
|
||||
if( sc && sc->data[SC_BASILICA] )
|
||||
casttime = -1; // No Casting time on basilica cancel
|
||||
break;
|
||||
case KN_CHARGEATK:
|
||||
{
|
||||
unsigned int k = (distance_bl(src,target)-1)/3; //+100% every 3 cells of distance
|
||||
if( k > 2 ) k = 2; // ...but hard-limited to 300%.
|
||||
casttime += casttime * k;
|
||||
}
|
||||
break;
|
||||
case GD_EMERGENCYCALL: //Emergency Call double cast when the user has learned Leap [Daegaladh]
|
||||
if( sd && pc_checkskill(sd,TK_HIGHJUMP) )
|
||||
casttime *= 2;
|
||||
switch(skill_id) {
|
||||
case ALL_RESURRECTION:
|
||||
if(battle_check_undead(tstatus->race,tstatus->def_ele)) {
|
||||
combo = 1;
|
||||
} else if (!status_isdead(target))
|
||||
return 0; //Can't cast on non-dead characters.
|
||||
break;
|
||||
case RA_WUGDASH:
|
||||
if (sc && sc->data[SC_WUGDASH])
|
||||
casttime = -1;
|
||||
case MO_FINGEROFFENSIVE:
|
||||
if(sd)
|
||||
casttime += casttime * min(skill_lv, sd->spiritball);
|
||||
break;
|
||||
case EL_WIND_SLASH:
|
||||
case EL_HURRICANE:
|
||||
case EL_TYPOON_MIS:
|
||||
case EL_STONE_HAMMER:
|
||||
case EL_ROCK_CRUSHER:
|
||||
case EL_STONE_RAIN:
|
||||
case EL_ICE_NEEDLE:
|
||||
case EL_WATER_SCREW:
|
||||
case EL_TIDAL_WEAPON:
|
||||
if( src->type == BL_ELEM ){
|
||||
sd = BL_CAST(BL_PC, battle_get_master(src));
|
||||
if( sd && sd->skill_id_old == SO_EL_ACTION ){
|
||||
case MO_EXTREMITYFIST:
|
||||
if (sc && sc->data[SC_COMBO] &&
|
||||
(sc->data[SC_COMBO]->val1 == MO_COMBOFINISH ||
|
||||
sc->data[SC_COMBO]->val1 == CH_TIGERFIST ||
|
||||
sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH))
|
||||
casttime = -1;
|
||||
sd->skill_id_old = 0;
|
||||
}
|
||||
}
|
||||
combo = 1;
|
||||
break;
|
||||
case SR_GATEOFHELL:
|
||||
case SR_TIGERCANNON:
|
||||
if (sc && sc->data[SC_COMBO] &&
|
||||
sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE)
|
||||
casttime = -1;
|
||||
combo = 1;
|
||||
break;
|
||||
case SA_SPELLBREAKER:
|
||||
combo = 1;
|
||||
break;
|
||||
case ST_CHASEWALK:
|
||||
if (sc && sc->data[SC_CHASEWALK])
|
||||
casttime = -1;
|
||||
break;
|
||||
case TK_RUN:
|
||||
if (sc && sc->data[SC_RUN])
|
||||
casttime = -1;
|
||||
break;
|
||||
case HP_BASILICA:
|
||||
if( sc && sc->data[SC_BASILICA] )
|
||||
casttime = -1; // No Casting time on basilica cancel
|
||||
break;
|
||||
case KN_CHARGEATK:
|
||||
{
|
||||
unsigned int k = (distance_bl(src,target)-1)/3; //+100% every 3 cells of distance
|
||||
if( k > 2 ) k = 2; // ...but hard-limited to 300%.
|
||||
casttime += casttime * k;
|
||||
}
|
||||
break;
|
||||
case GD_EMERGENCYCALL: //Emergency Call double cast when the user has learned Leap [Daegaladh]
|
||||
if( sd && pc_checkskill(sd,TK_HIGHJUMP) )
|
||||
casttime *= 2;
|
||||
break;
|
||||
case RA_WUGDASH:
|
||||
if (sc && sc->data[SC_WUGDASH])
|
||||
casttime = -1;
|
||||
break;
|
||||
case EL_WIND_SLASH:
|
||||
case EL_HURRICANE:
|
||||
case EL_TYPOON_MIS:
|
||||
case EL_STONE_HAMMER:
|
||||
case EL_ROCK_CRUSHER:
|
||||
case EL_STONE_RAIN:
|
||||
case EL_ICE_NEEDLE:
|
||||
case EL_WATER_SCREW:
|
||||
case EL_TIDAL_WEAPON:
|
||||
if( src->type == BL_ELEM ){
|
||||
sd = BL_CAST(BL_PC, battle_get_master(src));
|
||||
if( sd && sd->skill_id_old == SO_EL_ACTION ){
|
||||
casttime = -1;
|
||||
sd->skill_id_old = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// moved here to prevent Suffragium from ending if skill fails
|
||||
@ -1344,40 +1349,37 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv);
|
||||
#endif
|
||||
|
||||
if (src->type == BL_NPC) { // NPC-objects do not have cast time
|
||||
if (src->type == BL_NPC) // NPC-objects do not have cast time
|
||||
casttime = 0;
|
||||
}
|
||||
|
||||
if(!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026
|
||||
unit_stop_walking(src,1);// eventhough this is not how official works but this will do the trick. bugreport:6829
|
||||
// in official this is triggered even if no cast time.
|
||||
clif_skillcasting(src, src->id, target_id, 0,0, skill_id, skill_get_ele(skill_id, skill_lv), casttime);
|
||||
if( casttime > 0 || combo )
|
||||
{
|
||||
if (sd && target->type == BL_MOB)
|
||||
{
|
||||
if( casttime > 0 || combo ) {
|
||||
if (sd && target->type == BL_MOB) {
|
||||
TBL_MOB *md = (TBL_MOB*)target;
|
||||
mobskill_event(md, src, tick, -1); //Cast targetted skill event.
|
||||
if (tstatus->mode&(MD_CASTSENSOR_IDLE|MD_CASTSENSOR_CHASE) &&
|
||||
battle_check_target(target, src, BCT_ENEMY) > 0)
|
||||
{
|
||||
switch (md->state.skillstate) {
|
||||
case MSS_RUSH:
|
||||
case MSS_FOLLOW:
|
||||
if (!(tstatus->mode&MD_CASTSENSOR_CHASE))
|
||||
case MSS_RUSH:
|
||||
case MSS_FOLLOW:
|
||||
if (!(tstatus->mode&MD_CASTSENSOR_CHASE))
|
||||
break;
|
||||
md->target_id = src->id;
|
||||
md->state.aggressive = (tstatus->mode&MD_ANGRY)?1:0;
|
||||
md->min_chase = md->db->range3;
|
||||
break;
|
||||
md->target_id = src->id;
|
||||
md->state.aggressive = (tstatus->mode&MD_ANGRY)?1:0;
|
||||
md->min_chase = md->db->range3;
|
||||
break;
|
||||
case MSS_IDLE:
|
||||
case MSS_WALK:
|
||||
if (!(tstatus->mode&MD_CASTSENSOR_IDLE))
|
||||
case MSS_IDLE:
|
||||
case MSS_WALK:
|
||||
if (!(tstatus->mode&MD_CASTSENSOR_IDLE))
|
||||
break;
|
||||
md->target_id = src->id;
|
||||
md->state.aggressive = (tstatus->mode&MD_ANGRY)?1:0;
|
||||
md->min_chase = md->db->range3;
|
||||
break;
|
||||
md->target_id = src->id;
|
||||
md->state.aggressive = (tstatus->mode&MD_ANGRY)?1:0;
|
||||
md->min_chase = md->db->range3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1388,13 +1390,11 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
|
||||
|
||||
if( !sd || sd->skillitem != skill_id || skill_get_cast(skill_id,skill_lv) )
|
||||
ud->canact_tick = tick + casttime + 100;
|
||||
if( sd )
|
||||
{
|
||||
switch( skill_id )
|
||||
{
|
||||
case CG_ARROWVULCAN:
|
||||
sd->canequip_tick = tick + casttime;
|
||||
break;
|
||||
if( sd ) {
|
||||
switch( skill_id ) {
|
||||
case CG_ARROWVULCAN:
|
||||
sd->canequip_tick = tick + casttime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ud->skilltarget = target_id;
|
||||
@ -1464,9 +1464,8 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
|
||||
if (sc && !sc->count)
|
||||
sc = NULL;
|
||||
|
||||
if( sd )
|
||||
{
|
||||
if( skillnotok(skill_id, sd) || !skill_check_condition_castbegin(sd, skill_id, skill_lv) )
|
||||
if( sd ) {
|
||||
if( skill_isNotOk(skill_id, sd) || !skill_check_condition_castbegin(sd, skill_id, skill_lv) )
|
||||
return 0;
|
||||
/**
|
||||
* "WHY IS IT HEREE": pneuma cannot be cancelled past this point, the client displays the animation even,
|
||||
@ -1486,8 +1485,14 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
|
||||
if (!status_check_skilluse(src, NULL, skill_id, 0))
|
||||
return 0;
|
||||
|
||||
if( map_getcell(src->m, skill_x, skill_y, CELL_CHKWALL) )
|
||||
{// can't cast ground targeted spells on wall cells
|
||||
//fail if the targetted skill is near NPC [Cydh]
|
||||
if(skill_get_inf2(skill_id)&INF2_NO_NEARNPC && skill_isNotOk_npcRange(src,NULL,skill_id,skill_lv,skill_x,skill_y)) {
|
||||
if (sd)
|
||||
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( map_getcell(src->m, skill_x, skill_y, CELL_CHKWALL) ) {// can't cast ground targeted spells on wall cells
|
||||
if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
|
||||
return 0;
|
||||
}
|
||||
@ -1520,9 +1525,8 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
|
||||
casttime = skill_vfcastfix(src, casttime, skill_id, skill_lv );
|
||||
#endif
|
||||
|
||||
if (src->type == BL_NPC) { // NPC-objects do not have cast time
|
||||
if (src->type == BL_NPC) // NPC-objects do not have cast time
|
||||
casttime = 0;
|
||||
}
|
||||
|
||||
ud->state.skillcastcancel = castcancel&&casttime>0?1:0;
|
||||
if( !sd || sd->skillitem != skill_id || skill_get_cast(skill_id,skill_lv) )
|
||||
|
Loading…
x
Reference in New Issue
Block a user