summaryrefslogtreecommitdiff
path: root/src/map/skill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/skill.c')
-rw-r--r--src/map/skill.c1773
1 files changed, 1436 insertions, 337 deletions
diff --git a/src/map/skill.c b/src/map/skill.c
index 51d0792e3..a7ed0b8f2 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -54,6 +54,7 @@
#include "common/strlib.h"
#include "common/timer.h"
#include "common/utils.h"
+#include "common/conf.h"
#include <math.h>
#include <stdio.h>
@@ -83,7 +84,8 @@ struct s_skill_dbs skilldbs;
struct skill_interface *skill;
//Since only mob-casted splash skills can hit ice-walls
-static inline int splash_target(struct block_list* bl) {
+int skill_splash_target(struct block_list* bl)
+{
#ifndef RENEWAL
return ( bl->type == BL_MOB ) ? BL_SKILL|BL_CHAR : BL_CHAR;
#else // Some skills can now hit ground skills(traps, ice wall & etc.)
@@ -579,11 +581,20 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd)
return 1;
}
break;
-
+ default:
+ return skill->not_ok_unknown(skill_id, sd);
}
return (map->list[m].flag.noskill);
}
+int skill_notok_unknown(uint16 skill_id, struct map_session_data *sd)
+{
+ int16 m;
+ nullpo_retr (1, sd);
+ m = sd->bl.m;
+ return (map->list[m].flag.noskill);
+}
+
int skillnotok_hom(uint16 skill_id, struct homun_data *hd)
{
uint16 idx = skill->get_index(skill_id);
@@ -610,12 +621,20 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd)
if(hd->sc.data[SC_GOLDENE_FERSE])
return 1;
break;
+ default:
+ return skill->not_ok_hom_unknown(skill_id, hd);
}
//Use master's criteria.
return skill->not_ok(skill_id, hd->master);
}
+int skillnotok_hom_unknown(uint16 skill_id, struct homun_data *hd)
+{
+ //Use master's criteria.
+ return skill->not_ok(skill_id, hd->master);
+}
+
int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md)
{
uint16 idx = skill->get_index(skill_id);
@@ -1546,17 +1565,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
sd->state.autocast = 1;
skill->consume_requirement(sd,temp,auto_skill_lv,1);
skill->toggle_magicpower(src, temp);
- switch (type) {
- case CAST_GROUND:
- skill->castend_pos2(src, tbl->x, tbl->y, temp, auto_skill_lv, tick, 0);
- break;
- case CAST_NODAMAGE:
- skill->castend_nodamage_id(src, tbl, temp, auto_skill_lv, tick, 0);
- break;
- case CAST_DAMAGE:
- skill->castend_damage_id(src, tbl, temp, auto_skill_lv, tick, 0);
- break;
- }
+ skill->castend_type(type, src, tbl, temp, auto_skill_lv, tick, 0);
sd->state.autocast = 0;
//Set canact delay. [Skotlex]
ud = unit->bl2ud(src);
@@ -1684,11 +1693,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1
sd->state.autocast = 1;
sd->autospell3[i].lock = true;
skill->consume_requirement(sd,temp,skill_lv,1);
- switch( type ) {
- case CAST_GROUND: skill->castend_pos2(&sd->bl, tbl->x, tbl->y, temp, skill_lv, tick, 0); break;
- case CAST_NODAMAGE: skill->castend_nodamage_id(&sd->bl, tbl, temp, skill_lv, tick, 0); break;
- case CAST_DAMAGE: skill->castend_damage_id(&sd->bl, tbl, temp, skill_lv, tick, 0); break;
- }
+ skill->castend_type(type, &sd->bl, tbl, temp, skill_lv, tick, 0);
sd->autospell3[i].lock = false;
sd->state.autocast = 0;
}
@@ -1898,17 +1903,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b
dstsd->state.autocast = 1;
skill->consume_requirement(dstsd,auto_skill_id,auto_skill_lv,1);
- switch (type) {
- case CAST_GROUND:
- skill->castend_pos2(bl, tbl->x, tbl->y, auto_skill_id, auto_skill_lv, tick, 0);
- break;
- case CAST_NODAMAGE:
- skill->castend_nodamage_id(bl, tbl, auto_skill_id, auto_skill_lv, tick, 0);
- break;
- case CAST_DAMAGE:
- skill->castend_damage_id(bl, tbl, auto_skill_id, auto_skill_lv, tick, 0);
- break;
- }
+ skill->castend_type(type, bl, tbl, auto_skill_id, auto_skill_lv, tick, 0);
dstsd->state.autocast = 0;
// Set canact delay. [Skotlex]
ud = unit->bl2ud(bl);
@@ -2005,7 +2000,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in
if (sd) {
for (i = 0; i < EQI_MAX; i++) {
int j = sd->equip_index[i];
- if (j < 0 || sd->status.inventory[j].attribute == 1 || !sd->inventory_data[j])
+ if (j < 0 || (sd->status.inventory[j].attribute & ATTR_BROKEN) != 0 || !sd->inventory_data[j])
continue;
switch(i) {
@@ -2031,7 +2026,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in
continue;
}
if (flag) {
- sd->status.inventory[j].attribute = 1;
+ sd->status.inventory[j].attribute |= ATTR_BROKEN;
pc->unequipitem(sd, j, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
}
}
@@ -2068,12 +2063,12 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int
return where?1:0;
}
/*=========================================================================
- Used to knock back players, monsters, traps, etc
- - 'count' is the number of squares to knock back
- - 'direction' indicates the way OPPOSITE to the knockback direction (or -1 for default behavior)
- - if 'flag&0x1', position update packets must not be sent.
- - if 'flag&0x2', skill blown ignores players' special_state.no_knockback
- -------------------------------------------------------------------------*/
+ * Used to knock back players, monsters, traps, etc
+ * 'count' is the number of squares to knock back
+ * 'direction' indicates the way OPPOSITE to the knockback direction (or -1 for default behavior)
+ * if 'flag&0x1', position update packets must not be sent.
+ * if 'flag&0x2', skill blown ignores players' special_state.no_knockback
+ */
int skill_blown(struct block_list* src, struct block_list* target, int count, int8 dir, int flag)
{
int dx = 0, dy = 0;
@@ -2890,11 +2885,11 @@ void skill_attack_display_unknown(int *attack_type, struct block_list* src, stru
}
int skill_attack_copy_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) {
- return *skill_id;
+ return *skill_id;
}
int skill_attack_dir_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag) {
- return -1;
+ return -1;
}
void skill_attack_blow_unknown(int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage, int8 *dir) {
@@ -3554,6 +3549,21 @@ int skill_reveal_trap(struct block_list *bl, va_list ap)
return 0;
}
+void skill_castend_type(int type, struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag)
+{
+ switch (type) {
+ case CAST_GROUND:
+ skill->castend_pos2(src, bl->x, bl->y, skill_id, skill_lv, tick, flag);
+ break;
+ case CAST_NODAMAGE:
+ skill->castend_nodamage_id(src, bl, skill_id, skill_lv, tick, flag);
+ break;
+ case CAST_DAMAGE:
+ skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, flag);
+ break;
+ }
+}
+
/*==========================================
*
*
@@ -3744,7 +3754,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
if (!(flag&1) && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_MONK) {
//Becomes a splash attack when Soul Linked.
map->foreachinrange(skill->area_sub, bl,
- skill->get_splash(skill_id, skill_lv),splash_target(src),
+ skill->get_splash(skill_id, skill_lv),skill->splash_target(src),
src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1,
skill->castend_damage_id);
} else
@@ -3755,7 +3765,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
skill->area_temp[1] = 0;
map->foreachinrange(skill->attack_area, src,
- skill->get_splash(skill_id, skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv), skill->splash_target(src),
BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
break;
@@ -3791,7 +3801,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
//line of sight between caster and target.
skill->area_temp[1] = bl->id;
map->foreachinpath(skill->attack_area,src->m,src->x,src->y,bl->x,bl->y,
- skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), skill->splash_target(src),
skill->get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY);
break;
@@ -3802,7 +3812,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case NPC_THUNDERBREATH:
skill->area_temp[1] = bl->id;
map->foreachinpath(skill->attack_area,src->m,src->x,src->y,bl->x,bl->y,
- skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv),skill->get_maxcount(skill_id,skill_lv), skill->splash_target(src),
skill->get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY);
break;
@@ -4005,7 +4015,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
skill->area_temp[0] = map->foreachinrange(skill->area_sub, bl, (skill_id == AS_SPLASHER)?1:skill->get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill->area_sub_count);
// recursive invocation of skill->castend_damage_id() with flag|1
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
}
break;
@@ -4086,9 +4096,9 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
// Splash around target cell, but only cells inside area; we first have to check the area is not negative
if((max(min_x,tx-1) <= min(max_x,tx+1)) &&
(max(min_y,ty-1) <= min(max_y,ty+1)) &&
- (map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count))) {
+ (map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count))) {
// Recursive call
- map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), splash_target(src), src, skill_id, skill_lv, tick, (flag|BCT_ENEMY)+1, skill->castend_damage_id);
+ map->foreachinarea(skill->area_sub, bl->m, max(min_x,tx-1), max(min_y,ty-1), min(max_x,tx+1), min(max_y,ty+1), skill->splash_target(src), src, skill_id, skill_lv, tick, (flag|BCT_ENEMY)+1, skill->castend_damage_id);
// Self-collision
if(bl->x >= min_x && bl->x <= max_x && bl->y >= min_y && bl->y <= max_y)
skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,(flag&0xFFF)>0?SD_ANIMATION:0);
@@ -4489,18 +4499,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
if( !skill->check_condition_castbegin(sd, spell_skill_id, spell_skill_lv) )
break;
- switch( skill->get_casttype(spell_skill_id) ) {
- case CAST_GROUND:
- skill->castend_pos2(src, bl->x, bl->y, spell_skill_id, spell_skill_lv, tick, 0);
- break;
- case CAST_NODAMAGE:
- skill->castend_nodamage_id(src, bl, spell_skill_id, spell_skill_lv, tick, 0);
- break;
- case CAST_DAMAGE:
- skill->castend_damage_id(src, bl, spell_skill_id, spell_skill_lv, tick, 0);
- break;
- }
-
+ skill->castend_type(skill->get_casttype(spell_skill_id), src, bl, spell_skill_id, spell_skill_lv, tick, 0);
sd->ud.canact_tick = tick + skill->delay_fix(src, spell_skill_id, spell_skill_lv);
clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, spell_skill_id, spell_skill_lv), 0, 0, 0);
@@ -4589,7 +4588,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); // Need confirm it.
} else {
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL);
if( sd ) pc->overheat(sd,1);
}
@@ -4607,7 +4606,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
// Destination area
skill->area_temp[4] = x;
skill->area_temp[5] = y;
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id);
skill->addtimerskill(src,tick + 800,src->id,x,y,skill_id,skill_lv,0,flag); // To teleport Self
clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,BDT_SKILL);
}
@@ -4666,7 +4665,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
status_change_end(bl, SC_HIDING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
} else{
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL);
}
break;
@@ -4803,7 +4802,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
if(flag & 1)
skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
else {
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill->castend_damage_id);
}
break;
@@ -4917,12 +4916,11 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
return 0;
}
- if( sd && ud->skilltimer != INVALID_TIMER && (pc->checkskill(sd,SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK) )
+ if (sd && ud->skilltimer != INVALID_TIMER && (pc->checkskill(sd, SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK || (skill->get_inf2(ud->skill_id) & INF2_FREE_CAST_REDUCED) != 0))
{// restore original walk speed
ud->skilltimer = INVALID_TIMER;
status_calc_bl(&sd->bl, SCB_SPEED|SCB_ASPD);
}
-
ud->skilltimer = INVALID_TIMER;
}
@@ -5219,7 +5217,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) {
bool skill_castend_id_unknown(struct unit_data *ud, struct block_list *src, struct block_list *target)
{
- return false;
+ return false;
}
/*==========================================
@@ -5455,7 +5453,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100;
if (heal_get_jobexp <= 0)
heal_get_jobexp = 1;
- pc->gainexp (sd, bl, 0, heal_get_jobexp, false);
+ pc->gainexp(sd, bl, 0, heal_get_jobexp, false);
}
}
break;
@@ -5531,7 +5529,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if (jexp < 1) jexp = 1;
}
if(exp > 0 || jexp > 0)
- pc->gainexp (sd, bl, exp, jexp, false);
+ pc->gainexp(sd, bl, exp, jexp, false);
}
}
}
@@ -6259,7 +6257,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
skill->area_temp[1] = 0;
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
map->foreachinrange(skill->area_sub, bl,
- skill->get_splash(skill_id, skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv), skill->splash_target(src),
src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1,
skill->castend_damage_id);
status_change_end(src, SC_HIDING, INVALID_TIMER);
@@ -6278,7 +6276,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
int count = 0;
skill->area_temp[1] = 0;
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
- count = map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src),
+ count = map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src),
src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id);
if( !count && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) )
clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL);
@@ -6324,7 +6322,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
skill->area_temp[1] = 0;
map->foreachinrange(skill->attack_area, src,
- skill->get_splash(skill_id, skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv), skill->splash_target(src),
BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
break;
@@ -6338,7 +6336,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
clif->skill_nodamage(src, src, skill_id, -1, 1);
map->delblock(src); //Required to prevent chain-self-destructions hitting back.
map->foreachinrange(skill->area_sub, bl,
- skill->get_splash(skill_id, skill_lv), splash_target(src),
+ skill->get_splash(skill_id, skill_lv), skill->splash_target(src),
src, skill_id, skill_lv, tick, flag|targetmask,
skill->castend_damage_id);
map->addblock(src);
@@ -6892,7 +6890,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
return 1;
}
if( skill_id == AM_BERSERKPITCHER ) {
- if( dstsd && dstsd->status.base_level < (unsigned int)sd->inventory_data[i]->elv ) {
+ if (dstsd && dstsd->status.base_level < sd->inventory_data[i]->elv) {
clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
map->freeblock_unlock();
return 1;
@@ -8735,7 +8733,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
int failure;
if( (failure = sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) )
{
- map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);;
+ map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),skill->splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);;
clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,BDT_SKILL);
if (sd) pc->overheat(sd,1);
}
@@ -8825,9 +8823,9 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
if (is_boss(bl)) break;
joblvbonus = ( sd ? sd->status.job_level : 50 );
//First we set the success chance based on the caster's build which increases the chance.
- rate = 10 * skill_lv + rnd_value( sstatus->dex / 12, sstatus->dex / 4 ) + joblvbonus + status->get_lv(src) / 10;
+ rate = 10 * skill_lv + rnd->value( sstatus->dex / 12, sstatus->dex / 4 ) + joblvbonus + status->get_lv(src) / 10;
// We then reduce the success chance based on the target's build.
- rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) + tstatus->luk / 10 + ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) + status->get_lv(bl) / 10;
+ rate -= rnd->value( tstatus->agi / 6, tstatus->agi / 3 ) + tstatus->luk / 10 + ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) + status->get_lv(bl) / 10;
//Finally we set the minimum success chance cap based on the caster's skill level and DEX.
rate = cap_value( rate, skill_lv + sstatus->dex / 20, 100);
clif->skill_nodamage(src,bl,skill_id,0,sc_start(src,bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)));
@@ -9076,7 +9074,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
clif->skill_nodamage(src, bl, skill_id, skill_lv, sp ? 1:0);
} else {
clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL);
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id);
}
break;
@@ -9768,7 +9766,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
}
} else {
skill->area_temp[2] = 0;
- map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id);
+ map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id);
}
break;
@@ -9899,17 +9897,17 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin
bool skill_castend_nodamage_id_dead_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
- return true;
+ return true;
}
bool skill_castend_nodamage_id_undead_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
- return true;
+ return true;
}
bool skill_castend_nodamage_id_mado_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
- return false;
+ return false;
}
bool skill_castend_nodamage_id_unknown(struct block_list *src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
@@ -9947,7 +9945,7 @@ int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
return 0;
}
- if( sd && ud->skilltimer != INVALID_TIMER && ( pc->checkskill(sd,SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK ) )
+ if (sd && ud->skilltimer != INVALID_TIMER && (pc->checkskill(sd, SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK || (skill->get_inf2(ud->skill_id) & INF2_FREE_CAST_REDUCED) != 0))
{// restore original walk speed
ud->skilltimer = INVALID_TIMER;
status_calc_bl(&sd->bl, SCB_SPEED|SCB_ASPD);
@@ -10083,7 +10081,7 @@ int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
}
-static int check_npc_chaospanic(struct block_list *bl, va_list args)
+int skill_check_npc_chaospanic(struct block_list *bl, va_list args)
{
const struct npc_data *nd = NULL;
@@ -10097,7 +10095,8 @@ static int check_npc_chaospanic(struct block_list *bl, va_list args)
return 1;
}
/* skill count without self */
-static int skill_count_wos(struct block_list *bl,va_list ap) {
+int skill_count_wos(struct block_list *bl, va_list ap)
+{
struct block_list* src = va_arg(ap, struct block_list*);
if( src->id != bl->id ) {
return 1;
@@ -10339,7 +10338,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case SC_CHAOSPANIC:
case SC_MAELSTROM:
- if (sd && map->foreachinarea(&check_npc_chaospanic,src->m, x-3, y-3, x+3, y+3, BL_NPC) > 0 ) {
+ if (sd && map->foreachinarea(skill->check_npc_chaospanic, src->m, x-3, y-3, x+3, y+3, BL_NPC) > 0 ) {
clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
@@ -10481,7 +10480,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
if( sc && sc->data[SC_BASILICA] )
status_change_end(src, SC_BASILICA, INVALID_TIMER); // Cancel Basilica
else { // Create Basilica. Start SC on caster. Unit timer start SC on others.
- if( map->foreachinrange(skill_count_wos, src, 2, BL_MOB|BL_PC, src) ) {
+ if( map->foreachinrange(skill->count_wos, src, 2, BL_MOB|BL_PC, src) ) {
if( sd )
clif->skill_fail(sd,skill_id,USESKILL_FAIL,0);
return 1;
@@ -10746,7 +10745,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case RK_DRAGONBREATH:
case RK_DRAGONBREATH_WATER:
r = skill->get_splash(skill_id,skill_lv);
- map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src),
+ map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src),
src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id);
break;
case WM_GREAT_ECHO:
@@ -10768,7 +10767,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
break;
case SO_ARRULLO:
r = skill->get_splash(skill_id,skill_lv);
- map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src),
+ map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src),
src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id);
break;
/**
@@ -10883,7 +10882,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case LG_RAYOFGENESIS:
if( status->charge(src,status_get_max_hp(src)*3*skill_lv / 100,0) ) {
r = skill->get_splash(skill_id,skill_lv);
- map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,splash_target(src),
+ map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,skill->splash_target(src),
src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id);
} else if( sd )
clif->skill_fail(sd,skill_id,USESKILL_FAIL,0);
@@ -11883,7 +11882,8 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick
return skill_id;
}
-void skill_unit_onplace_unknown(struct skill_unit *src, struct block_list *bl, int64 *tick) {
+void skill_unit_onplace_unknown(struct skill_unit *src, struct block_list *bl, int64 *tick)
+{
}
/*==========================================
@@ -12646,6 +12646,9 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
status->change_start(ss, bl, SC_BLIND, rnd() % 100 > sg->skill_lv * 10, sg->skill_lv, sg->skill_id, 0, 0,
skill->get_time2(sg->skill_id, sg->skill_lv), SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE);
break;
+ default:
+ skill->unit_onplace_timer_unknown(src, bl, &tick);
+ break;
}
if (bl->type == BL_MOB && ss != bl)
@@ -12653,6 +12656,11 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
return skill_id;
}
+
+void skill_unit_onplace_timer_unknown(struct skill_unit *src, struct block_list *bl, int64 *tick)
+{
+}
+
/*==========================================
* Triggered when a char steps out of a skill cell
*------------------------------------------*/
@@ -14063,22 +14071,22 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id
int skill_check_condition_castbegin_off_unknown(struct status_change *sc, uint16 *skill_id)
{
- return -1;
+ return -1;
}
int skill_check_condition_castbegin_mount_unknown(struct status_change *sc, uint16 *skill_id)
{
- return 0;
+ return 0;
}
int skill_check_condition_castbegin_madogear_unknown(struct status_change *sc, uint16 *skill_id)
{
- return 0;
+ return 0;
}
int skill_check_condition_castbegin_unknown(struct status_change *sc, uint16 *skill_id)
{
- return -1;
+ return -1;
}
int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) {
@@ -14701,12 +14709,12 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
bool skill_get_requirement_off_unknown(struct status_change *sc, uint16 *skill_id)
{
- return false;
+ return false;
}
bool skill_get_requirement_item_unknown(struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, uint16 *idx, int *i)
{
- return false;
+ return false;
}
void skill_get_requirement_unknown(struct status_change *sc, struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv, struct skill_condition *req)
@@ -15222,7 +15230,7 @@ void skill_repairweapon (struct map_session_data *sd, int idx) {
return; //Invalid index??
item = &target_sd->status.inventory[idx];
- if( item->nameid <= 0 || item->attribute == 0 )
+ if( item->nameid <= 0 || (item->attribute & ATTR_BROKEN) == 0 )
return; //Again invalid item....
if( sd != target_sd && !battle->check_range(&sd->bl,&target_sd->bl, skill->get_range2(&sd->bl, sd->menuskill_id,sd->menuskill_val2) ) ){
@@ -15241,7 +15249,8 @@ void skill_repairweapon (struct map_session_data *sd, int idx) {
clif->skill_nodamage(&sd->bl,&target_sd->bl,sd->menuskill_id,1,1);
- item->attribute = 0;/* clear broken state */
+ item->attribute |= ATTR_BROKEN;
+ item->attribute ^= ATTR_BROKEN; /* clear broken state */
clif->equiplist(target_sd);
@@ -15312,7 +15321,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
if( sd->status.class_ == JOB_MECHANIC_T )
per += 100;
else
- per += 5 * ((signed int)sd->status.job_level - 50);
+ per += 5 * (sd->status.job_level - 50);
pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE); // FIXME: is this the correct reason flag?
if (per > rnd() % 1000) {
@@ -16671,7 +16680,7 @@ int skill_unit_timer_sub(union DBKey key, struct DBData *data, va_list ap)
case UNT_FEINTBOMB: {
struct block_list *src = map->id2bl(group->src_id);
if( src ) {
- map->foreachinrange(skill->area_sub, &su->bl, su->range, splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|1, skill->castend_damage_id);
+ map->foreachinrange(skill->area_sub, &su->bl, su->range, skill->splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|1, skill->castend_damage_id);
status_change_end(src, SC__FEINTBOMB_MASTER, INVALID_TIMER);
}
skill->delunit(su);
@@ -18480,7 +18489,7 @@ void skill_init_unit_layout (void)
}
break;
default:
- ShowError("unknown unit layout at skill %d\n",i);
+ skill->init_unit_layout_unknown(i);
break;
}
if (!skill->dbs->unit_layout[pos].count)
@@ -18581,6 +18590,11 @@ void skill_init_unit_layout (void)
}
+void skill_init_unit_layout_unknown(int skill_idx)
+{
+ ShowError("unknown unit layout at skill %d\n", skill_idx);
+}
+
int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) {
int inf = 0;
struct status_change *sc = status->get_sc(bl);
@@ -18799,220 +18813,6 @@ void skill_cooldown_load(struct map_session_data * sd) {
}
}
-/*==========================================
- * sub-function of DB reading.
- * skill_db.txt
- *------------------------------------------*/
-bool skill_parse_row_skilldb(char* split[], int columns, int current) {
-// id,range,hit,inf,element,nk,splash,max,list_num,castcancel,cast_defence_rate,inf2,maxcount,skill_type,blow_count,name,description
- uint16 skill_id = atoi(split[0]);
- uint16 idx;
- if( (skill_id >= GD_SKILLRANGEMIN && skill_id <= GD_SKILLRANGEMAX)
- || (skill_id >= HM_SKILLRANGEMIN && skill_id <= HM_SKILLRANGEMAX)
- || (skill_id >= MC_SKILLRANGEMIN && skill_id <= MC_SKILLRANGEMAX)
- || (skill_id >= EL_SKILLRANGEMIN && skill_id <= EL_SKILLRANGEMAX) ) {
- ShowWarning("skill_parse_row_skilldb: Skill id %d is forbidden (interferes with guild/homun/mercenary skill mapping)!\n", skill_id);
- return false;
- }
-
- idx = skill->get_index(skill_id);
- if( !idx ) // invalid skill id
- return false;
-
- skill->dbs->db[idx].nameid = skill_id;
- skill->split_atoi(split[1],skill->dbs->db[idx].range);
- skill->dbs->db[idx].hit = atoi(split[2]);
- skill->dbs->db[idx].inf = atoi(split[3]);
- skill->split_atoi(split[4],skill->dbs->db[idx].element);
- skill->dbs->db[idx].nk = (int)strtol(split[5], NULL, 0);
- skill->split_atoi(split[6],skill->dbs->db[idx].splash);
- skill->dbs->db[idx].max = atoi(split[7]);
- skill->split_atoi(split[8],skill->dbs->db[idx].num);
-
- if( strcmpi(split[9],"yes") == 0 )
- skill->dbs->db[idx].castcancel = 1;
- else
- skill->dbs->db[idx].castcancel = 0;
- skill->dbs->db[idx].cast_def_rate = atoi(split[10]);
- skill->dbs->db[idx].inf2 = (int)strtol(split[11], NULL, 0);
- skill->split_atoi(split[12],skill->dbs->db[idx].maxcount);
- if( strcmpi(split[13],"weapon") == 0 )
- skill->dbs->db[idx].skill_type = BF_WEAPON;
- else if( strcmpi(split[13],"magic") == 0 )
- skill->dbs->db[idx].skill_type = BF_MAGIC;
- else if( strcmpi(split[13],"misc") == 0 )
- skill->dbs->db[idx].skill_type = BF_MISC;
- else
- skill->dbs->db[idx].skill_type = 0;
- skill->split_atoi(split[14],skill->dbs->db[idx].blewcount);
- safestrncpy(skill->dbs->db[idx].name, trim(split[15]), sizeof(skill->dbs->db[idx].name));
- safestrncpy(skill->dbs->db[idx].desc, trim(split[16]), sizeof(skill->dbs->db[idx].desc));
- strdb_iput(skill->name2id_db, skill->dbs->db[idx].name, skill_id);
- script->set_constant2(skill->dbs->db[idx].name, (int)skill_id, false, false);
-
- return true;
-}
-
-bool skill_parse_row_requiredb(char* split[], int columns, int current) {
-// skill_id,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10
- char* p;
- int j;
-
- uint16 skill_id = atoi(split[0]);
- uint16 idx = skill->get_index(skill_id);
- if( !idx ) // invalid skill id
- return false;
-
- skill->split_atoi(split[1],skill->dbs->db[idx].hp);
- skill->split_atoi(split[2],skill->dbs->db[idx].mhp);
- skill->split_atoi(split[3],skill->dbs->db[idx].sp);
- skill->split_atoi(split[4],skill->dbs->db[idx].hp_rate);
- skill->split_atoi(split[5],skill->dbs->db[idx].sp_rate);
- skill->split_atoi(split[6],skill->dbs->db[idx].zeny);
-
- //Which weapon type are required, see doc/item_db for types
- p = split[7];
- for( j = 0; j < 32; j++ ) {
- int l = atoi(p);
- if( l == 99 ) { // Any weapon
- skill->dbs->db[idx].weapon = 0;
- break;
- } else
- skill->dbs->db[idx].weapon |= 1<<l;
- p = strchr(p,':');
- if(!p)
- break;
- p++;
- }
-
- //FIXME: document this
- p = split[8];
- for( j = 0; j < 32; j++ ) {
- int l = atoi(p);
- if( l == 99 ) { // Any ammo type
- skill->dbs->db[idx].ammo = 0xFFFFFFFF;
- break;
- } else if( l ) // 0 stands for no requirement
- skill->dbs->db[idx].ammo |= 1<<l;
- p = strchr(p,':');
- if( !p )
- break;
- p++;
- }
- skill->split_atoi(split[9],skill->dbs->db[idx].ammo_qty);
-
- if( strcmpi(split[10],"hiding") == 0 ) skill->dbs->db[idx].state = ST_HIDING;
- else if( strcmpi(split[10],"cloaking") == 0 ) skill->dbs->db[idx].state = ST_CLOAKING;
- else if( strcmpi(split[10],"hidden") == 0 ) skill->dbs->db[idx].state = ST_HIDDEN;
- else if( strcmpi(split[10],"riding") == 0 ) skill->dbs->db[idx].state = ST_RIDING;
- else if( strcmpi(split[10],"falcon") == 0 ) skill->dbs->db[idx].state = ST_FALCON;
- else if( strcmpi(split[10],"cart") == 0 ) skill->dbs->db[idx].state = ST_CART;
- else if( strcmpi(split[10],"shield") == 0 ) skill->dbs->db[idx].state = ST_SHIELD;
- else if( strcmpi(split[10],"sight") == 0 ) skill->dbs->db[idx].state = ST_SIGHT;
- else if( strcmpi(split[10],"explosionspirits") == 0 ) skill->dbs->db[idx].state = ST_EXPLOSIONSPIRITS;
- else if( strcmpi(split[10],"cartboost") == 0 ) skill->dbs->db[idx].state = ST_CARTBOOST;
- else if( strcmpi(split[10],"recover_weight_rate") == 0 ) skill->dbs->db[idx].state = ST_RECOV_WEIGHT_RATE;
- else if( strcmpi(split[10],"move_enable") == 0 ) skill->dbs->db[idx].state = ST_MOVE_ENABLE;
- else if( strcmpi(split[10],"water") == 0 ) skill->dbs->db[idx].state = ST_WATER;
- else if( strcmpi(split[10],"dragon") == 0 ) skill->dbs->db[idx].state = ST_RIDINGDRAGON;
- else if( strcmpi(split[10],"warg") == 0 ) skill->dbs->db[idx].state = ST_WUG;
- else if( strcmpi(split[10],"ridingwarg") == 0 ) skill->dbs->db[idx].state = ST_RIDINGWUG;
- else if( strcmpi(split[10],"mado") == 0 ) skill->dbs->db[idx].state = ST_MADO;
- else if( strcmpi(split[10],"elementalspirit") == 0 ) skill->dbs->db[idx].state = ST_ELEMENTALSPIRIT;
- else if( strcmpi(split[10],"poisonweapon") == 0 ) skill->dbs->db[idx].state = ST_POISONINGWEAPON;
- else if( strcmpi(split[10],"rollingcutter") == 0 ) skill->dbs->db[idx].state = ST_ROLLINGCUTTER;
- else if( strcmpi(split[10],"mh_fighting") == 0 ) skill->dbs->db[idx].state = ST_MH_FIGHTING;
- else if( strcmpi(split[10],"mh_grappling") == 0 ) skill->dbs->db[idx].state = ST_MH_GRAPPLING;
- else if( strcmpi(split[10],"peco") == 0 ) skill->dbs->db[idx].state = ST_PECO;
- /**
- * Unknown or no state
- **/
- else skill->dbs->db[idx].state = ST_NONE;
-
- skill->split_atoi(split[11],skill->dbs->db[idx].spiritball);
- for( j = 0; j < MAX_SKILL_ITEM_REQUIRE; j++ ) {
- skill->dbs->db[idx].itemid[j] = atoi(split[12+ 2*j]);
- skill->dbs->db[idx].amount[j] = atoi(split[13+ 2*j]);
- }
-
- return true;
-}
-
-bool skill_parse_row_castdb(char* split[], int columns, int current) {
-// skill_id,CastingTime,AfterCastActDelay,AfterCastWalkDelay,Duration1,Duration2
- uint16 skill_id = atoi(split[0]);
- uint16 idx = skill->get_index(skill_id);
- if( !idx ) // invalid skill id
- return false;
-
- skill->split_atoi(split[1],skill->dbs->db[idx].cast);
- skill->split_atoi(split[2],skill->dbs->db[idx].delay);
- skill->split_atoi(split[3],skill->dbs->db[idx].walkdelay);
- skill->split_atoi(split[4],skill->dbs->db[idx].upkeep_time);
- skill->split_atoi(split[5],skill->dbs->db[idx].upkeep_time2);
- skill->split_atoi(split[6],skill->dbs->db[idx].cooldown);
-#ifdef RENEWAL_CAST
- skill->split_atoi(split[7],skill->dbs->db[idx].fixed_cast);
-#endif
- return true;
-}
-
-bool skill_parse_row_castnodexdb(char* split[], int columns, int current) {
-// Skill id,Cast,Delay (optional)
- uint16 skill_id = atoi(split[0]);
- uint16 idx = skill->get_index(skill_id);
- if( !idx ) // invalid skill id
- return false;
-
- skill->split_atoi(split[1],skill->dbs->db[idx].castnodex);
- if( split[2] ) // optional column
- skill->split_atoi(split[2],skill->dbs->db[idx].delaynodex);
-
- return true;
-}
-
-bool skill_parse_row_unitdb(char* split[], int columns, int current) {
-// ID,unit ID,unit ID 2,layout,range,interval,target,flag
- uint16 skill_id = atoi(split[0]);
- uint16 idx = skill->get_index(skill_id);
- if( !idx ) // invalid skill id
- return false;
-
- skill->dbs->db[idx].unit_id[0] = (int)strtol(split[1],NULL,16);
- skill->dbs->db[idx].unit_id[1] = (int)strtol(split[2],NULL,16);
- skill->split_atoi(split[3],skill->dbs->db[idx].unit_layout_type);
- skill->split_atoi(split[4],skill->dbs->db[idx].unit_range);
- skill->dbs->db[idx].unit_interval = atoi(split[5]);
-
- if( strcmpi(split[6],"noenemy")==0 ) skill->dbs->db[idx].unit_target = BCT_NOENEMY;
- else if( strcmpi(split[6],"friend")==0 ) skill->dbs->db[idx].unit_target = BCT_NOENEMY;
- else if( strcmpi(split[6],"party")==0 ) skill->dbs->db[idx].unit_target = BCT_PARTY;
- else if( strcmpi(split[6],"ally")==0 ) skill->dbs->db[idx].unit_target = BCT_PARTY|BCT_GUILD;
- else if( strcmpi(split[6],"guild")==0 ) skill->dbs->db[idx].unit_target = BCT_GUILD;
- else if( strcmpi(split[6],"all")==0 ) skill->dbs->db[idx].unit_target = BCT_ALL;
- else if( strcmpi(split[6],"enemy")==0 ) skill->dbs->db[idx].unit_target = BCT_ENEMY;
- else if( strcmpi(split[6],"self")==0 ) skill->dbs->db[idx].unit_target = BCT_SELF;
- else if( strcmpi(split[6],"sameguild")==0 ) skill->dbs->db[idx].unit_target = BCT_GUILD|BCT_SAMEGUILD;
- else if( strcmpi(split[6],"noone")==0 ) skill->dbs->db[idx].unit_target = BCT_NOONE;
- else skill->dbs->db[idx].unit_target = (int)strtol(split[6],NULL,16);
-
- skill->dbs->db[idx].unit_flag = (int)strtol(split[7],NULL,16);
-
- if (skill->dbs->db[idx].unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy)
- skill->dbs->db[idx].unit_target = BCT_NOENEMY;
-
- //By default, target just characters.
- skill->dbs->db[idx].unit_target |= BL_CHAR;
- if (skill->dbs->db[idx].unit_flag&UF_NOPC)
- skill->dbs->db[idx].unit_target &= ~BL_PC;
- if (skill->dbs->db[idx].unit_flag&UF_NOMOB)
- skill->dbs->db[idx].unit_target &= ~BL_MOB;
- if (skill->dbs->db[idx].unit_flag&UF_SKILL)
- skill->dbs->db[idx].unit_target |= BL_SKILL;
-
- return true;
-}
-
bool skill_parse_row_producedb(char* split[], int columns, int current) {
// ProduceItemID,ItemLV,RequireSkill,Requireskill_lv,MaterialID1,MaterialAmount1,......
int x,y;
@@ -19181,14 +18981,1297 @@ bool skill_parse_row_changematerialdb(char* split[], int columns, int current) {
return true;
}
+#define skilldb_duplicate_warning(name, setting, skill) (ShowError("skill_read_skilldb: Duplicate entry '%s' in setting '%s' for Skill Id %d in '%s', skipping...\n", name, setting, skill, "db/"DBPATH"skill_db.conf"))
+#define skilldb_invalid_error(name, setting, skill) (ShowError("skill_read_skilldb: Invalid entry '%s' in setting '%s' for Skill Id %d in '%s', skipping...\n", name, setting, skill, "db/"DBPATH"skill_db.conf"))
+
+/**
+ * Sets Level based configuration for skill groups from skill_db.conf [ Smokexyz/Hercules ]
+ * @param *conf pointer to config setting.
+ * @param *arr pointer to array to be set.
+ */
+void skill_config_set_level(struct config_setting_t *conf, int *arr)
+{
+ int i=0;
+
+ if (config_setting_is_group(conf)) {
+ for (i=0; i<MAX_SKILL_LEVEL; i++) {
+ char level[5];
+ sprintf(level, "Lv%d", i+1);
+ libconfig->setting_lookup_int(conf, level, &arr[i]);
+ }
+ } else if (config_setting_is_array(conf)) {
+ for (i=0; i<config_setting_length(conf) && i < MAX_SKILL_LEVEL; i++) {
+ arr[i] = libconfig->setting_get_int_elem(conf, i);
+ }
+ } else {
+ int val=libconfig->setting_get_int(conf);
+ for(i=0; i<MAX_SKILL_LEVEL; i++) {
+ arr[i] = val;
+ }
+ }
+}
+
+/**
+ * Sets all values in a skill level array to a specified value [ Smokexyz/Hercules ]
+ * @param *arr pointer to array being parsed.
+ * @param value value being set for the array.
+ * @return (void)
+ */
+void skill_level_set_value(int *arr, int value)
+{
+ int i=0;
+
+ for(i=0; i<MAX_SKILL_LEVEL; i++) {
+ arr[i] = value;
+ }
+}
+
+void skill_validate_hittype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ const char *type = NULL;
+
+ if (libconfig->setting_lookup_string(conf, "Hit", &type)) {
+ if (strcmpi(type, "BDT_SKILL") == 0) {
+ sk->hit = BDT_SKILL;
+ } else if (strcmpi(type, "BDT_MULTIHIT") == 0) {
+ sk->hit = BDT_MULTIHIT;
+ } else if (strcmpi(type, "BDT_NORMAL") == 0) {
+ sk->hit = BDT_NORMAL;
+ } else {
+ skilldb_invalid_error(type, "Hit", sk->nameid);
+ return;
+ }
+ }
+}
+
+/**
+ * Validates "SkillType" when reading skill_db.conf
+ * @param conf struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_skilltype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *t = NULL, *tt = NULL;
+
+ if((t=libconfig->setting_get_member(conf, "SkillType")) && config_setting_is_group(t)) {
+ int j=0;
+ while ((tt = libconfig->setting_get_elem(t, j++))) {
+ const char *type = config_setting_name(tt);
+ bool on = libconfig->setting_get_bool_real(tt);
+
+ if (strcmpi(type, "Enemy") == 0) {
+ if (on) {
+ sk->inf |= INF_ATTACK_SKILL;
+ } else {
+ sk->inf &= ~INF_ATTACK_SKILL;
+ }
+ } else if (strcmpi(type, "Place") == 0) {
+ if (on) {
+ sk->inf |= INF_GROUND_SKILL;
+ } else {
+ sk->inf &= ~INF_GROUND_SKILL;
+ }
+ } else if (strcmpi(type, "Self") == 0) {
+ if (on) {
+ sk->inf |= INF_SELF_SKILL;
+ } else {
+ sk->inf &= ~INF_SELF_SKILL;
+ }
+ } else if (strcmpi(type, "Friend") == 0) {
+ if (on) {
+ sk->inf |= INF_SUPPORT_SKILL;
+ } else {
+ sk->inf &= ~INF_SUPPORT_SKILL;
+ }
+ } else if (strcmpi(type, "Trap") == 0) {
+ if (on) {
+ sk->inf |= INF_TARGET_TRAP;
+ } else {
+ sk->inf &= ~INF_TARGET_TRAP;
+ }
+ } else if (strcmpi(type, "Passive") != 0) {
+ skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
+ }
+ }
+ }
+}
+
+/**
+ * Validates "SkillInfo" when reading skill_db.conf
+ * @param conf struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_skillinfo(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *t = NULL, *tt = NULL;
+
+ if ((t=libconfig->setting_get_member(conf, "SkillInfo")) && config_setting_is_group(t)) {
+ int j=0;
+ while ((tt = libconfig->setting_get_elem(t, j++))) {
+ const char *type = config_setting_name(tt);
+ bool on = libconfig->setting_get_bool_real(tt);
+
+ if (strcmpi(type, "Quest") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_QUEST_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_QUEST_SKILL;
+ }
+ } else if (strcmpi(type, "NPC") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_NPC_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_NPC_SKILL;
+ }
+ } else if (strcmpi(type, "Wedding") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_WEDDING_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_WEDDING_SKILL;
+ }
+ } else if (strcmpi(type, "Spirit") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_SPIRIT_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_SPIRIT_SKILL;
+ }
+ } else if (strcmpi(type, "Guild") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_GUILD_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_GUILD_SKILL;
+ }
+ } else if (strcmpi(type, "Song") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_SONG_DANCE;
+ } else {
+ sk->inf2 &= ~INF2_SONG_DANCE;
+ }
+ } else if (strcmpi(type, "Ensemble") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_ENSEMBLE_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_ENSEMBLE_SKILL;
+ }
+ } else if (strcmpi(type, "Trap") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_TRAP;
+ } else {
+ sk->inf2 &= ~INF2_TRAP;
+ }
+ } else if (strcmpi(type, "TargetSelf") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_TARGET_SELF;
+ } else {
+ sk->inf2 &= ~INF2_TARGET_SELF;
+ }
+ } else if (strcmpi(type, "NoCastSelf") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_NO_TARGET_SELF;
+ } else {
+ sk->inf2 &= ~INF2_NO_TARGET_SELF;
+ }
+ } else if (strcmpi(type, "PartyOnly") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_PARTY_ONLY;
+ } else {
+ sk->inf2 &= ~INF2_PARTY_ONLY;
+ }
+ } else if (strcmpi(type, "GuildOnly") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_GUILD_ONLY;
+ } else {
+ sk->inf2 &= ~INF2_GUILD_ONLY;
+ }
+ } else if (strcmpi(type, "NoEnemy") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_NO_ENEMY;
+ } else {
+ sk->inf2 &= ~INF2_NO_ENEMY;
+ }
+ } else if (strcmpi(type, "IgnoreLandProtector") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_NOLP;
+ } else {
+ sk->inf2 &= ~INF2_NOLP;
+ }
+ } else if (strcmpi(type, "Chorus") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_CHORUS_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_CHORUS_SKILL;
+ }
+ } else if (strcmpi(type, "FreeCastNormal") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_FREE_CAST_NORMAL;
+ } else {
+ sk->inf2 &= ~INF2_FREE_CAST_NORMAL;
+ }
+ } else if (strcmpi(type, "FreeCastReduced") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_FREE_CAST_REDUCED;
+ } else {
+ sk->inf2 &= ~INF2_FREE_CAST_REDUCED;
+ }
+ } else if (strcmpi(type, "None") != 0) {
+ skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
+ }
+ }
+ }
+}
+
+/**
+ * Validates "AttackType" when reading skill_db.conf
+ * @param conf struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_attacktype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ const char *type = NULL;
+
+ if (libconfig->setting_lookup_string(conf, "AttackType", &type)) {
+ if (!strcmpi(type, "Weapon")) {
+ sk->skill_type = BF_WEAPON;
+ } else if (!strcmpi(type, "Magic")) {
+ sk->skill_type = BF_MAGIC;
+ } else if (!strcmpi(type, "Misc")) {
+ sk->skill_type = BF_MISC;
+ } else {
+ skilldb_invalid_error(type, "AttackType", sk->nameid);
+ return;
+ }
+ }
+}
+
+/**
+ * Validates "Element" when reading skill_db.conf
+ * @param ele_t struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_element(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ const char *type = NULL;
+ struct config_setting_t *t = NULL;
+
+ if ((t=libconfig->setting_get_member(conf, "Element")) && config_setting_is_group(t)) {
+ int j = 0;
+ char lv[5];
+
+ for (j=0; j < MAX_SKILL_LEVEL; j++) {
+ sprintf(lv, "Lv%d",j+1);
+ if (libconfig->setting_lookup_string(t, lv, &type)) {
+ if (strcmpi(type,"Ele_Weapon") == 0)
+ sk->element[j] = -1;
+ else if (strcmpi(type,"Ele_Endowed") == 0)
+ sk->element[j] = -2;
+ else if (strcmpi(type,"Ele_Random") == 0)
+ sk->element[j] = -3;
+ else if (!script->get_constant(type,&sk->element[j]))
+ skilldb_invalid_error(type, config_setting_name(conf), sk->nameid);
+ }
+ }
+
+ } else if (libconfig->setting_lookup_string(conf, "Element", &type)) {
+ int ele = 0;
+
+ if (strcmpi(type,"Ele_Weapon") == 0)
+ ele = -1;
+ else if (strcmpi(type,"Ele_Endowed") == 0)
+ ele = -2;
+ else if (strcmpi(type,"Ele_Random") == 0)
+ ele = -3;
+ else if (!script->get_constant(type, &ele)) {
+ skilldb_invalid_error(type, config_setting_name(conf), sk->nameid);
+ return;
+ }
+
+ skill->level_set_value(sk->element, ele);
+ }
+}
+
+/**
+ * Validates "DamageType" when reading skill_db.conf
+ * @param conf struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_damagetype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *t = NULL, *tt = NULL;
+
+ if ((t=libconfig->setting_get_member(conf, "DamageType")) && config_setting_is_group(t)) {
+ int j=0;
+ while ((tt = libconfig->setting_get_elem(t, j++))) {
+ const char *type = config_setting_name(tt);
+ bool on = libconfig->setting_get_bool_real(tt);
+
+ if (strcmpi(type, "NoDamage") == 0) {
+ if (on) {
+ sk->nk |= NK_NO_DAMAGE;
+ } else {
+ sk->nk &= ~NK_NO_DAMAGE;
+ }
+ } else if (strcmpi(type, "SplashArea") == 0) {
+ if (on) {
+ sk->nk |= NK_SPLASH_ONLY;
+ } else {
+ sk->nk &= ~NK_SPLASH_ONLY;
+ }
+ } else if (strcmpi(type, "SplitDamage") == 0) {
+ if (on) {
+ sk->nk |= NK_SPLASHSPLIT;
+ } else {
+ sk->nk &= ~NK_SPLASHSPLIT;
+ }
+ } else if (strcmpi(type, "IgnoreCards") == 0) {
+ if (on) {
+ sk->nk |= NK_NO_CARDFIX_ATK;
+ } else {
+ sk->nk &= ~NK_NO_CARDFIX_ATK;
+ }
+ } else if (strcmpi(type, "IgnoreElement") == 0) {
+ if (on) {
+ sk->nk |= NK_NO_ELEFIX;
+ } else {
+ sk->nk &= ~NK_NO_ELEFIX;
+ }
+ } else if (strcmpi(type, "IgnoreDefense") == 0) {
+ if (on) {
+ sk->nk |= NK_IGNORE_DEF;
+ } else {
+ sk->nk &= ~NK_IGNORE_DEF;
+ }
+ } else if (strcmpi(type, "IgnoreFlee") == 0) {
+ if (on) {
+ sk->nk |= NK_IGNORE_FLEE;
+ } else {
+ sk->nk &= ~NK_IGNORE_FLEE;
+ }
+ } else if (strcmpi(type, "IgnoreDefCards") == 0) {
+ if (on) {
+ sk->nk |= NK_NO_CARDFIX_DEF;
+ } else {
+ sk->nk &= ~NK_NO_CARDFIX_DEF;
+ }
+ } else {
+ skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
+ }
+ }
+ }
+}
+
+/**
+ * Validates "SkillCast/DelayOptions" when reading skill_db.conf
+ * @param conf struct, pointer to skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @param delay boolean, switch for cast/delay setting
+ * @return (void)
+ */
+void skill_validate_castnodex(struct config_setting_t *conf, struct s_skill_db *sk, bool delay)
+{
+ struct config_setting_t *t = NULL, *tt = NULL;
+
+ if ((t=libconfig->setting_get_member(conf, delay?"SkillDelayOptions":"CastTimeOptions")) && config_setting_is_group(t)) {
+ int j = 0, tmpopt = 0;
+ while ((tt = libconfig->setting_get_elem(t, j++)) && j < 4) {
+ const char *type = config_setting_name(tt);
+ bool on = libconfig->setting_get_bool_real(tt);
+
+ if (strcmpi(type, "IgnoreDex") == 0) {
+ if (on) {
+ tmpopt |= 1<<0;
+ } else {
+ tmpopt &= ~(1<<0);
+ }
+ } else if (strcmpi(type, "IgnoreStatusEffect") == 0) {
+ if (on) {
+ tmpopt |= 1<<1;
+ } else {
+ tmpopt &= ~(1<<1);
+ }
+ } else if (strcmpi(type, "IgnoreItemBonus") == 0) {
+ if (on) {
+ tmpopt |= 1<<2;
+ } else {
+ tmpopt &= ~(1<<2);
+ }
+ } else {
+ skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
+ return;
+ }
+
+ }
+ skill->level_set_value(delay?sk->delaynodex:sk->castnodex, tmpopt);
+ }
+}
+
+/**
+ * Validates the "WeaponTypes" flag
+ * when parsing skill_db.conf
+ * @param *type const char, weapon type flag
+ * @param on boolean, switch for the flag
+ * @param *sk struct, pointer to s_skill_db
+ * @return void
+ */
+int skill_validate_weapontype_sub(const char *type, bool on, struct s_skill_db *sk )
+{
+ if (strcmpi(type, "NoWeapon") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_FIST;
+ } else {
+ sk->weapon &= ~(1<<W_FIST);
+ }
+ } else if (strcmpi(type, "Daggers") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DAGGER;
+ } else {
+ sk->weapon &= ~(1<<W_DAGGER);
+ }
+ } else if (strcmpi(type, "1HSwords") == 0) {
+
+ if (on) {
+ sk->weapon |= 1<<W_1HSWORD;
+ } else {
+ sk->weapon &= ~(1<<W_1HSWORD);
+ }
+ } else if (strcmpi(type, "2HSwords") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_2HSWORD;
+ } else {
+ sk->weapon &= ~(1<<W_2HSWORD);
+ }
+ } else if (strcmpi(type, "1HSpears") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_1HSPEAR;
+ } else {
+ sk->weapon &= ~(1<<W_1HSPEAR);
+ }
+ } else if (strcmpi(type, "2HSpears") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_2HSPEAR;
+ } else {
+ sk->weapon &= ~(1<<W_2HSPEAR);
+ }
+ } else if (strcmpi(type, "1HAxes") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_1HAXE;
+ } else {
+ sk->weapon &= ~(1<<W_1HAXE);
+ }
+ } else if (strcmpi(type, "2HAxes") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_2HAXE;
+ } else {
+ sk->weapon &= ~(1<<W_2HAXE);
+ }
+ } else if (strcmpi(type, "Maces") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_MACE;
+ } else {
+ sk->weapon &= ~(1<<W_MACE);
+ }
+ } else if (strcmpi(type, "2HMaces") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_2HMACE;
+ } else {
+ sk->weapon &= ~(1<<W_2HMACE);
+ }
+ } else if (strcmpi(type, "Staves") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_STAFF;
+ } else {
+ sk->weapon &= ~(1<<W_STAFF);
+ }
+ } else if (strcmpi(type, "Bows") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_BOW;
+ } else {
+ sk->weapon &= ~(1<<W_BOW);
+ }
+ } else if (strcmpi(type, "Knuckles") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_KNUCKLE;
+ } else {
+ sk->weapon &= ~(1<<W_KNUCKLE);
+ }
+ } else if (strcmpi(type, "Instruments") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_MUSICAL;
+ } else {
+ sk->weapon &= ~(1<<W_MUSICAL);
+ }
+ } else if (strcmpi(type, "Whips") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_WHIP;
+ } else {
+ sk->weapon &= ~(1<<W_WHIP);
+ }
+ } else if (strcmpi(type, "Books") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_BOOK;
+ } else {
+ sk->weapon &= ~(1<<W_BOOK);
+ }
+ } else if (strcmpi(type, "Katars") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_KATAR;
+ } else {
+ sk->weapon &= ~(1<<W_KATAR);
+ }
+ } else if (strcmpi(type, "Revolvers") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_REVOLVER;
+ } else {
+ sk->weapon &= ~(1<<W_REVOLVER);
+ }
+ } else if (strcmpi(type, "Rifles") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_RIFLE;
+ } else {
+ sk->weapon &= ~(1<<W_RIFLE);
+ }
+ } else if (strcmpi(type, "GatlingGuns") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_GATLING;
+ } else {
+ sk->weapon &= ~(1<<W_GATLING);
+ }
+ } else if (strcmpi(type, "Shotguns") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_SHOTGUN;
+ } else {
+ sk->weapon &= ~(1<<W_SHOTGUN);
+ }
+ } else if (strcmpi(type, "GrenadeLaunchers") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_GRENADE;
+ } else {
+ sk->weapon &= ~(1<<W_GRENADE);
+ }
+ } else if (strcmpi(type, "FuumaShurikens") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_HUUMA;
+ } else {
+ sk->weapon &= ~(1<<W_HUUMA);
+ }
+ } else if (strcmpi(type, "2HStaves") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_2HSTAFF;
+ } else {
+ sk->weapon &= ~(1<<W_2HSTAFF);
+ }
+ }
+ /* MAX_SINGLE_WEAPON_TYPE excluded */
+ else if (strcmpi(type, "DWDaggers") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_DD;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_DD);
+ }
+ } else if (strcmpi(type, "DWSwords") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_SS;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_SS);
+ }
+ } else if (strcmpi(type, "DWAxes") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_AA;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_AA);
+ }
+ } else if (strcmpi(type, "DWDaggerSword") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_DS;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_DS);
+ }
+ } else if (strcmpi(type, "DWDaggerAxe") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_DA;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_DA);
+ }
+ } else if (strcmpi(type, "DWSwordAxe") == 0) {
+ if (on) {
+ sk->weapon |= 1<<W_DOUBLE_SA;
+ } else {
+ sk->weapon &= ~(1<<W_DOUBLE_SA);
+ }
+ } else if (strcmpi(type, "All") == 0) {
+ sk->weapon = 0;
+ } else {
+ ShowError("Item %d. Unknown weapon type %s\n", sk->nameid, type);
+ return 1; // invalid type
+ }
+
+ return 0;
+}
+
+/**
+ * Validates "WeaponTypes"
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_weapontype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *tt = NULL;
+ const char *type = NULL;
+
+ if ((tt = libconfig->setting_get_member(conf, "WeaponTypes")) && config_setting_is_group(tt)) {
+ int j = 0;
+ struct config_setting_t *wpt = NULL;
+ while ((wpt = libconfig->setting_get_elem(tt, j++)) != NULL) {
+ if (skill_validate_weapontype_sub(config_setting_name(wpt), libconfig->setting_get_bool_real(wpt), sk))
+ skilldb_invalid_error(config_setting_name(wpt), config_setting_name(tt), sk->nameid);
+ }
+ } else if (libconfig->setting_lookup_string(conf, "WeaponTypes", &type)) {
+ if (skill_validate_weapontype_sub(type, true, sk))
+ skilldb_invalid_error(type, "WeaponTypes", sk->nameid);
+ }
+}
+
+/**
+ * Validates the "AmmoTypes" flag
+ * when parsing skill_db.conf
+ * @param type string, ammo type flag
+ * @param on boolean, switch for the flag
+ * @param sk struct, pointer to s_skill_db
+ * @return void
+ */
+int skill_validate_ammotype_sub(const char *type, bool on, struct s_skill_db *sk)
+{
+ if (strcmpi(type, "A_ARROW") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_ARROW;
+ } else {
+ sk->ammo &= ~(1<<A_ARROW);
+ }
+ } else if (strcmpi(type, "A_DAGGER") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_DAGGER;
+ } else {
+ sk->ammo &= ~(1<<A_DAGGER);
+ }
+ } else if (strcmpi(type, "A_BULLET") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_BULLET;
+ } else {
+ sk->ammo &= ~(1<<A_BULLET);
+ }
+ } else if (strcmpi(type, "A_SHELL") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_SHELL;
+ } else {
+ sk->ammo &= ~(1<<A_SHELL);
+ }
+ } else if (strcmpi(type, "A_GRENADE") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_GRENADE;
+ } else {
+ sk->ammo &= ~(1<<A_GRENADE);
+ }
+ } else if (strcmpi(type, "A_SHURIKEN") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_SHURIKEN;
+ } else {
+ sk->ammo &= ~(1<<A_SHURIKEN);
+ }
+ } else if (strcmpi(type, "A_KUNAI") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_KUNAI;
+ } else {
+ sk->ammo &= ~(1<<A_KUNAI);
+ }
+ } else if (strcmpi(type, "A_CANNONBALL") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_CANNONBALL;
+ } else {
+ sk->ammo &= ~(1<<A_CANNONBALL);
+ }
+ } else if (strcmpi(type, "A_THROWWEAPON") == 0) {
+ if (on) {
+ sk->ammo |= 1<<A_THROWWEAPON;
+ } else {
+ sk->ammo &= ~(1<<A_THROWWEAPON);
+ }
+ } else if (strcmpi(type, "All") == 0) {
+ if (on) {
+ sk->ammo = 0xFFFFFFFF;
+ } else {
+ sk->ammo = 0;
+ }
+ } else {
+ return 1; // Invalid Entry
+ }
+
+ return 0;
+}
+
+/**
+ * Validates the "AmmoTypes" flag
+ * when parsing skill_db.conf
+ * @param conf pointer to the skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return void
+ */
+void skill_validate_ammotype(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *tt = NULL;
+ const char *tstr = NULL;
+
+ if ((tt = libconfig->setting_get_member(conf, "AmmoTypes")) && config_setting_is_group(tt)) {
+ int j = 0;
+ struct config_setting_t *amt = { 0 };
+ while ((amt = libconfig->setting_get_elem(tt, j++))) {
+ if (skill_validate_ammotype_sub(config_setting_name(amt), libconfig->setting_get_bool_real(amt), sk))
+ skilldb_invalid_error(config_setting_name(amt), config_setting_name(tt), sk->nameid);
+ }
+ } else if( libconfig->setting_lookup_string(conf, "AmmoTypes", &tstr)) {
+ if (skill_validate_ammotype_sub(tstr, true, sk))
+ skilldb_invalid_error(tstr, "AmmoTypes", sk->nameid);
+ }
+}
+
+/**
+ * Validates the "State" flag
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return void
+ */
+void skill_validate_state(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ const char *type = NULL;
+
+ if (libconfig->setting_lookup_string(conf, "State", &type) && strcmpi(type,"None") != ST_NONE) {
+ if ( strcmpi(type,"Hiding") == 0 ) sk->state = ST_HIDING;
+ else if (strcmpi(type,"Cloaking") == 0 ) sk->state = ST_CLOAKING;
+ else if (strcmpi(type,"Hidden") == 0 ) sk->state = ST_HIDDEN;
+ else if (strcmpi(type,"Riding") == 0 ) sk->state = ST_RIDING;
+ else if (strcmpi(type,"Falcon") == 0 ) sk->state = ST_FALCON;
+ else if (strcmpi(type,"Cart") == 0 ) sk->state = ST_CART;
+ else if (strcmpi(type,"Shield") == 0 ) sk->state = ST_SHIELD;
+ else if (strcmpi(type,"Sight") == 0 ) sk->state = ST_SIGHT;
+ else if (strcmpi(type,"ExplosionSpirits") == 0 ) sk->state = ST_EXPLOSIONSPIRITS;
+ else if (strcmpi(type,"CartBoost") == 0 ) sk->state = ST_CARTBOOST;
+ else if (strcmpi(type,"NotOverWeight") == 0 ) sk->state = ST_RECOV_WEIGHT_RATE;
+ else if (strcmpi(type,"Moveable") == 0 ) sk->state = ST_MOVE_ENABLE;
+ else if (strcmpi(type,"InWater") == 0 ) sk->state = ST_WATER;
+ else if (strcmpi(type,"Dragon") == 0 ) sk->state = ST_RIDINGDRAGON;
+ else if (strcmpi(type,"Warg") == 0 ) sk->state = ST_WUG;
+ else if (strcmpi(type,"RidingWarg") == 0 ) sk->state = ST_RIDINGWUG;
+ else if (strcmpi(type,"MadoGear") == 0 ) sk->state = ST_MADO;
+ else if (strcmpi(type,"ElementalSpirit") == 0 ) sk->state = ST_ELEMENTALSPIRIT;
+ else if (strcmpi(type,"PoisonWeapon") == 0 ) sk->state = ST_POISONINGWEAPON;
+ else if (strcmpi(type,"RollingCutter") == 0 ) sk->state = ST_ROLLINGCUTTER;
+ else if (strcmpi(type,"MH_Fighting") == 0 ) sk->state = ST_MH_FIGHTING;
+ else if (strcmpi(type,"MH_Grappling") == 0 ) sk->state = ST_MH_GRAPPLING;
+ else if (strcmpi(type,"Peco") == 0 ) sk->state = ST_PECO;
+ else
+ skilldb_invalid_error(type, "State", sk->nameid);
+ }
+}
+
+/**
+ * Validates the "Items" flag
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return void
+ */
+void skill_validate_item_requirements(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *tt = NULL;
+
+ if ((tt=libconfig->setting_get_member(conf, "Items")) && config_setting_is_group(conf)) {
+ int itx=-1;
+ struct config_setting_t *it;
+
+ while((it=libconfig->setting_get_elem(tt, ++itx)) && itx < MAX_SKILL_ITEM_REQUIRE) {
+ const char *type = config_setting_name(it);
+
+ if( type[0] == 'I' && type[1] == 'D' && itemdb->exists(atoi(type+2)) )
+ sk->itemid[itx] = atoi(type+2);
+ else if(!script->get_constant(type, &sk->itemid[itx])) {
+ ShowWarning("skill_read_skilldb: Invalid required Item '%s' given for skill Id %d in '%s', skipping...\n",type, sk->nameid, DBPATH"skill_db.conf");
+ continue;
+ }
+
+ if (config_setting_is_group(it)) {
+ // TODO: Per-level item requirements are not implemented yet!
+ // We just take the first level for the time being (old txt behavior)
+ sk->amount[itx] = libconfig->setting_get_int_elem(it, 0);
+ } else {
+ sk->amount[itx] = libconfig->setting_get_int(it);
+ }
+ }
+ }
+}
+
+/**
+ * Validates the "Unit > Target" flag
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, pointer to s_skill_db
+ * @return void
+ */
+void skill_validate_unit_target(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ const char *type = NULL;
+
+ if(libconfig->setting_lookup_string(conf, "Target", &type)) {
+
+ if(!strcmpi(type,"NotEnemy")) sk->unit_target = BCT_NOENEMY;
+ else if(!strcmpi(type,"NotParty")) sk->unit_target = BCT_NOPARTY;
+ else if (!strcmpi(type,"NotGuild")) sk->unit_target = BCT_NOGUILD;
+ else if(!strcmpi(type,"Friend")) sk->unit_target = BCT_NOENEMY;
+ else if(!strcmpi(type,"Party")) sk->unit_target = BCT_PARTY;
+ else if(!strcmpi(type,"Ally")) sk->unit_target = BCT_PARTY|BCT_GUILD;
+ else if(!strcmpi(type,"Guild")) sk->unit_target = BCT_GUILD;
+ else if(!strcmpi(type,"All")) sk->unit_target = BCT_ALL;
+ else if(!strcmpi(type,"Enemy")) sk->unit_target = BCT_ENEMY;
+ else if(!strcmpi(type,"Self")) sk->unit_target = BCT_SELF;
+ else if(!strcmpi(type,"SameGuild")) sk->unit_target = BCT_GUILD|BCT_SAMEGUILD;
+ }
+
+ if (sk->unit_flag & UF_DEFNOTENEMY && battle_config.defnotenemy)
+ sk->unit_target = BCT_NOENEMY;
+
+ //By default, target just characters.
+ sk->unit_target |= BL_CHAR;
+
+ if (sk->unit_flag & UF_NOPC)
+ sk->unit_target &= ~BL_PC;
+ if (sk->unit_flag & UF_NOMOB)
+ sk->unit_target &= ~BL_MOB;
+ if (sk->unit_flag & UF_SKILL)
+ sk->unit_target |= BL_SKILL;
+}
+
+/**
+ * Validates the "Unit > Flag" setting
+ * when parsing skill_db.conf
+ * @param type const char, name of the flag being parsed.
+ * @param on boolean, switch for flag setting
+ * @param sk struct, pointer to s_skill_db.
+ * @return (void)
+ */
+int skill_validate_unit_flag_sub(const char *type, bool on, struct s_skill_db *sk)
+{
+ if (strcmpi(type, "UF_DEFNOTENEMY") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_DEFNOTENEMY;
+ } else {
+ sk->unit_flag &= ~UF_DEFNOTENEMY;
+ }
+ } else if (strcmpi(type, "UF_NOREITERATION") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_NOREITERATION;
+ } else {
+ sk->unit_flag &= ~UF_NOREITERATION;
+ }
+ } else if (strcmpi(type, "UF_NOFOOTSET") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_NOFOOTSET;
+ } else {
+ sk->unit_flag &= ~UF_NOFOOTSET;
+ }
+ } else if (strcmpi(type, "UF_NOOVERLAP") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_NOOVERLAP;
+ } else {
+ sk->unit_flag &= ~UF_NOOVERLAP;
+ }
+ } else if (strcmpi(type, "UF_PATHCHECK") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_PATHCHECK;
+ } else {
+ sk->unit_flag &= ~UF_PATHCHECK;
+ }
+ } else if (strcmpi(type, "UF_NOPC") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_NOPC;
+ } else {
+ sk->unit_flag &= ~UF_NOPC;
+ }
+ } else if (strcmpi(type, "UF_NOMOB") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_NOMOB;
+ } else {
+ sk->unit_flag &= ~UF_NOMOB;
+ }
+ } else if (strcmpi(type, "UF_SKILL") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_SKILL;
+ } else {
+ sk->unit_flag &= ~UF_SKILL;
+ }
+ } else if (strcmpi(type, "UF_DANCE") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_DANCE;
+ } else {
+ sk->unit_flag &= ~UF_DANCE;
+ }
+ } else if (strcmpi(type, "UF_ENSEMBLE") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_ENSEMBLE;
+ } else {
+ sk->unit_flag &= ~UF_ENSEMBLE;
+ }
+ } else if (strcmpi(type, "UF_SONG") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_SONG;
+ } else {
+ sk->unit_flag &= ~UF_SONG;
+ }
+ } else if (strcmpi(type, "UF_DUALMODE") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_DUALMODE;
+ } else {
+ sk->unit_flag &= ~UF_DUALMODE;
+ }
+ } else if (strcmpi(type, "UF_RANGEDSINGLEUNIT") == 0) {
+ if (on) {
+ sk->unit_flag |= UF_RANGEDSINGLEUNIT;
+ } else {
+ sk->unit_flag &= ~UF_RANGEDSINGLEUNIT;
+ }
+ } else {
+ return 1; // Invalid Type
+ }
+
+ return 0;
+}
+
+/**
+ * Validate "Unit > Flag" setting
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_unit_flag(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ struct config_setting_t *t = NULL;
+
+ if ((t=libconfig->setting_get_member(conf, "Flag")) && config_setting_is_group(t)) {
+ int j=0;
+ struct config_setting_t *tt = NULL;
+ while ((tt = libconfig->setting_get_elem(t, j++))) {
+ const char *name = config_setting_name(tt);
+
+ if (skill_validate_unit_flag_sub(name, libconfig->setting_get_bool_real(tt), sk))
+ skilldb_invalid_error(name, config_setting_name(t), sk->nameid);
+ }
+ }
+}
+/**
+ * Validate additional field settings via plugins
+ * when parsing skill_db.conf
+ * @param conf struct, pointer to the skill configuration
+ * @param sk struct, struct, pointer to s_skill_db
+ * @return (void)
+ */
+void skill_validate_additional_fields(struct config_setting_t *conf, struct s_skill_db *sk)
+{
+ // Does nothing like a boss. *cough* plugins *cough*
+}
+
+/**
+ * Validates a skill entry and adds it to the database. [ Smokexyz/Hercules ]
+ * @param sk contains skill data to be checked.
+ * @param *source filepath constant.
+ * @return boolean true on success.
+ */
+bool skill_validate_skilldb(struct s_skill_db *sk, const char *source)
+{
+ int idx = skill->get_index(sk->nameid);
+
+ if (idx == 0) {
+ ShowWarning("skill_validate_skilldb: Invalid skill Id %d provided in '%s'! ... skipping\n", sk->nameid, source);
+ ShowInfo("It is possible that the skill Id is 0 or unavailable (interferes with guild/homun/mercenary skill mapping).\n");
+ return false;
+ } else if (sk->max <= 0) {
+ ShowError("skill_validate_skilldb: Invalid Max Level %d specified for skill Id %d in '%s', skipping...\n", sk->max, sk->nameid, source);
+ return false;
+ }
+
+ /* Direct assignment of temporary skill storage to skill db */
+ skill->dbs->db[idx] = *sk;
+ /* Put skill name in name2id DB */
+ strdb_iput(skill->name2id_db, skill->dbs->db[idx].name, skill->dbs->db[idx].nameid);
+ /* Set Name to Id script constants */
+ script->set_constant2(skill->dbs->db[idx].name, (int)skill->dbs->db[idx].nameid, false, false);
+
+ return true;
+}
+
+/**
+ * Reads skill_db.conf from relative filepath and processes [ Smokexyz/Hercules ]
+ * entries into the skill database.
+ * @param filename contains the file path and name.
+ * @return boolean true on success
+ */
+bool skill_read_skilldb(const char *filename)
+{
+ struct config_t skilldb;
+ struct config_setting_t *sk, *conf;
+ char filepath[256];
+ int count=0, index=0;
+ bool duplicate[MAX_SKILL] = {0};
+
+ nullpo_retr(false, filename);
+
+ sprintf(filepath,"db/%s",filename);
+
+ if (!libconfig->load_file(&skilldb, filepath)) {
+ return false; // Libconfig error report.
+ }
+
+ // Possible Syntax error.
+ if ((sk=libconfig->setting_get_member(skilldb.root, "skill_db")) == NULL) {
+ ShowError("skill_read_skilldb: Skill DB could not be loaded, please check '%s'.\n", filepath);
+ libconfig->destroy(&skilldb);
+ return false;
+ }
+
+ while ((conf = libconfig->setting_get_elem(sk,index++))) {
+ int idx=0, skill_id=0, temp=0;
+ struct config_setting_t *t = NULL, *tt = NULL;
+ struct s_skill_db tmp_db = { 0 };
+
+ /* Skill ID */
+ if (!libconfig->setting_lookup_int(conf, "Id", &skill_id)) {
+ ShowError("skill_read_skilldb: Skill Id not specified for entry %d in '%s', skipping...\n", index, filepath );
+ continue;
+ }
+
+ tmp_db.nameid = skill_id;
+
+ if((idx = skill->get_index(skill_id)) == 0) {
+ ShowError("skill_read_skilldb: Skill Id %d is out of range, or within a reserved range (for guild, homunculus, mercenary or elemental skills). skipping...\n", idx);
+ continue;
+ }
+
+ if (duplicate[idx]) {
+ ShowWarning("skill_read_skilldb: Duplicate Skill Id %d in entry %d in '%s', skipping...\n", skill_id, index, filepath);
+ continue;
+ }
+
+ /* Skill Name Constant */
+ if (!libconfig->setting_lookup_mutable_string(conf, "Name", tmp_db.name, sizeof(tmp_db.name))) {
+ ShowError("skill_read_skilldb: Name not specified for skill Id %d in '%s', skipping...\n", skill_id, filepath);
+ continue;
+ }
+
+ /* Skill Description */
+ libconfig->setting_lookup_mutable_string(conf, "Description", tmp_db.desc, sizeof(tmp_db.desc));
+
+ /* Max Level */
+ if (!libconfig->setting_lookup_int(conf, "MaxLevel", &temp)) {
+ ShowError("skill_read_skilldb: MaxLevel not specified for skill Id %d in '%s', skipping...\n", skill_id, filepath);
+ continue;
+ } else {
+ tmp_db.max = temp;
+ }
+
+ /* Range */
+ if ((t=libconfig->setting_get_member(conf, "Range")))
+ skill->config_set_level(t, tmp_db.range);
+
+ /* Hit Type */
+ skill->validate_hittype(conf, &tmp_db);
+
+ /* Skill Type */
+ skill->validate_skilltype(conf, &tmp_db);
+
+ /* Skill Info */
+ skill->validate_skillinfo(conf, &tmp_db);
+
+ /* Skill Attack Type */
+ skill->validate_attacktype(conf, &tmp_db);
+
+ /* Skill Element */
+ skill->validate_element(conf, &tmp_db);
+
+ /* Damage Type */
+ skill->validate_damagetype(conf, &tmp_db);
+
+ /* Splash Range */
+ if ((t = libconfig->setting_get_member(conf, "SplashRange")))
+ skill->config_set_level(t, tmp_db.splash);
+
+ /* Number of Hits */
+ if ((t = libconfig->setting_get_member(conf, "NumberOfHits")) && config_setting_is_group(t))
+ skill->config_set_level(t, tmp_db.num);
+ else if ((libconfig->setting_lookup_int(conf, "NumberOfHits", &temp)))
+ skill->level_set_value(tmp_db.num, temp);
+ else
+ skill->level_set_value(tmp_db.num, 1); // Default 1
+
+ /* Interrupt Cast */
+ if (libconfig->setting_lookup_bool(conf, "InterruptCast", &tmp_db.castcancel) == CONFIG_FALSE)
+ tmp_db.castcancel = 0;
+
+ /* Cast Defense Rate */
+ libconfig->setting_lookup_int(conf, "CastDefRate", &tmp_db.cast_def_rate);
+
+ /* Skill Instances */
+ if ((t = libconfig->setting_get_member(conf, "SkillInstances")))
+ skill->config_set_level(t, tmp_db.maxcount);
+
+ /* Knock-Back Tiles */
+ if ((t = libconfig->setting_get_member(conf, "KnockBackTiles")))
+ skill->config_set_level(t, tmp_db.blewcount);
+ /**
+ * Skill Cast / Delay data handling
+ */
+ /* Cast Time */
+ if ((t=libconfig->setting_get_member(conf, "CastTime")))
+ skill->config_set_level(t, tmp_db.cast);
+
+ /* After Cast Act Delay */
+ if ((t=libconfig->setting_get_member(conf, "AfterCastActDelay")))
+ skill->config_set_level(t, tmp_db.delay);
+
+ /* After Cast Walk Delay */
+ if ((t=libconfig->setting_get_member(conf, "AfterCastWalkDelay")))
+ skill->config_set_level(t, tmp_db.walkdelay);
+
+ /* Skill Data/Duration */
+ if ((t=libconfig->setting_get_member(conf, "SkillData1")))
+ skill->config_set_level(t, tmp_db.upkeep_time);
+
+ /* Skill Data/Duration 2 */
+ if ((t=libconfig->setting_get_member(conf, "SkillData2")))
+ skill->config_set_level(t, tmp_db.upkeep_time2);
+
+ /* Skill Cool Down */
+ if ((t=libconfig->setting_get_member(conf, "CoolDown")))
+ skill->config_set_level(t, tmp_db.cooldown);
+
+#ifdef RENEWAL_CAST
+ /* Fixed Casting Time */
+ if ((t=libconfig->setting_get_member(conf, "FixedCastTime")))
+ skill->config_set_level(t, tmp_db.fixed_cast);
+#endif
+ /* Cast Time Options */
+ skill->validate_castnodex(conf, &tmp_db, false);
+ skill->validate_castnodex(conf, &tmp_db, true);
+
+ /**
+ * Skill Requirements data handling
+ */
+ if ((t=libconfig->setting_get_member(conf, "Requirements")) && config_setting_is_group(t)) {
+
+ /* HP Costs */
+ if ((tt = libconfig->setting_get_member(t, "HPCost")))
+ skill->config_set_level(tt, tmp_db.hp);
+
+ /* Max HP Trigger */
+ if ((tt = libconfig->setting_get_member(t, "MaxHPTrigger")))
+ skill->config_set_level(tt, tmp_db.mhp);
+
+ /* SP Cost */
+ if ((tt = libconfig->setting_get_member(t, "SPCost")))
+ skill->config_set_level(tt, tmp_db.sp);
+
+ /* HP Rate */
+ if ((tt = libconfig->setting_get_member(t, "HPRateCost")))
+ skill->config_set_level(tt, tmp_db.hp_rate);
+
+ /* SP Rate */
+ if ((tt = libconfig->setting_get_member(t, "SPRateCost")))
+ skill->config_set_level(tt, tmp_db.sp_rate);
+
+ /* Zeny Cost */
+ if ((tt = libconfig->setting_get_member(t, "ZenyCost")))
+ skill->config_set_level(tt, tmp_db.zeny);
+
+ /* Spirit Sphere Cost */
+ if ((tt = libconfig->setting_get_member(t, "SpiritSphereCost")))
+ skill->config_set_level(tt, tmp_db.spiritball);
+
+ /* Weapon Types */
+ skill->validate_weapontype(t, &tmp_db);
+
+ /* Ammunition Types */
+ skill->validate_ammotype(t, &tmp_db);
+
+ /* Ammunition Amount */
+ if ((tt = libconfig->setting_get_member(t, "AmmoAmount")))
+ skill->config_set_level(tt, tmp_db.ammo_qty);
+
+ /* State */
+ skill->validate_state(t, &tmp_db);
+
+ /* Spirit Sphere Cost */
+ if ((tt = libconfig->setting_get_member(t, "SpiritSphereCost")))
+ skill->config_set_level(tt, tmp_db.spiritball);
+
+ /* Item Requirements and Amounts */
+ skill->validate_item_requirements(t, &tmp_db);
+ }
+
+ /**
+ * Skill Unit data handling
+ */
+ if ((t=libconfig->setting_get_member(conf, "Unit")) && config_setting_is_group(t)) {
+
+ /* Unit IDs [1,2] */
+ if ((tt=libconfig->setting_get_member(t, "Id")) && config_setting_is_array(tt)) {
+ tmp_db.unit_id[0] = libconfig->setting_get_int_elem(tt, 0);
+ tmp_db.unit_id[1] = libconfig->setting_get_int_elem(tt, 1);
+ } else {
+ libconfig->setting_lookup_int(t, "Id", &tmp_db.unit_id[0]);
+ }
+
+ /* Layout */
+ if((tt=libconfig->setting_get_member(t, "Layout")))
+ skill->config_set_level(tt, tmp_db.unit_layout_type);
+
+ /* Range */
+ if((tt=libconfig->setting_get_member(t, "Range")))
+ skill->config_set_level(tt, tmp_db.unit_range);
+
+ /* Interval */
+ if(libconfig->setting_lookup_int(t, "Interval", &temp))
+ tmp_db.unit_interval = temp;
+
+ /* Flag */
+ skill->validate_unit_flag(t, &tmp_db);
+
+ /* Target */
+ skill->validate_unit_target(t, &tmp_db);
+ }
+
+ /* Additional Fields for Plugins */
+ skill->validate_additional_fields(conf, &tmp_db);
+
+ // Validate the skill entry, add it to the duplicate array and increment count on success.
+ if ((duplicate[idx] = skill->validate_skilldb(&tmp_db, filepath)))
+ count++;
+ }
+
+ libconfig->destroy(&skilldb);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+
+ return true;
+}
+
+#undef skilldb_duplicate_warning
+#undef skilldb_invalid_error
+
/*===============================
* DB reading.
- * skill_db.txt
- * skill_require_db.txt
- * skill_cast_db.txt
- * skill_castnodex_db.txt
- * skill_nocast_db.txt
- * skill_unit_db.txt
* produce_db.txt
* create_arrow_db.txt
* abra_db.txt
@@ -19206,26 +20289,19 @@ void skill_readdb(bool minimal) {
safestrncpy(skill->dbs->db[0].name, "UNKNOWN_SKILL", sizeof(skill->dbs->db[0].name));
safestrncpy(skill->dbs->db[0].desc, "Unknown Skill", sizeof(skill->dbs->db[0].desc));
+ itemdb->name_constants(); // refresh ItemDB constants before loading of skills
+
#ifdef ENABLE_CASE_CHECK
- script->parser_current_file = DBPATH"skill_db.txt";
+ script->parser_current_file = DBPATH"skill_db.conf";
#endif // ENABLE_CASE_CHECK
- sv->readdb(map->db_path, DBPATH"skill_db.txt", ',', 17, 17, MAX_SKILL_DB, skill->parse_row_skilldb);
+ skill->read_skilldb(DBPATH"skill_db.conf");
#ifdef ENABLE_CASE_CHECK
script->parser_current_file = NULL;
#endif // ENABLE_CASE_CHECK
if (minimal)
return;
-
- sv->readdb(map->db_path, DBPATH"skill_require_db.txt", ',', 32, 32, MAX_SKILL_DB, skill->parse_row_requiredb);
-#ifdef RENEWAL_CAST
- sv->readdb(map->db_path, "re/skill_cast_db.txt", ',', 8, 8, MAX_SKILL_DB, skill->parse_row_castdb);
-#else
- sv->readdb(map->db_path, "pre-re/skill_cast_db.txt", ',', 7, 7, MAX_SKILL_DB, skill->parse_row_castdb);
-#endif
- sv->readdb(map->db_path, DBPATH"skill_castnodex_db.txt", ',', 2, 3, MAX_SKILL_DB, skill->parse_row_castnodexdb);
- sv->readdb(map->db_path, DBPATH"skill_unit_db.txt", ',', 8, 8, MAX_SKILL_DB, skill->parse_row_unitdb);
-
+
skill->init_unit_layout();
sv->readdb(map->db_path, "produce_db.txt", ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill->parse_row_producedb);
sv->readdb(map->db_path, "create_arrow_db.txt", ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill->parse_row_createarrowdb);
@@ -19405,6 +20481,7 @@ void skill_defaults(void) {
skill->is_combo = skill_is_combo;
skill->name2id = skill_name2id;
skill->isammotype = skill_isammotype;
+ skill->castend_type = skill_castend_type;
skill->castend_id = skill_castend_id;
skill->castend_pos = skill_castend_pos;
skill->castend_map = skill_castend_map;
@@ -19450,7 +20527,9 @@ void skill_defaults(void) {
skill->can_cloak = skill_can_cloak;
skill->enchant_elemental_end = skill_enchant_elemental_end;
skill->not_ok = skillnotok;
+ skill->not_ok_unknown = skill_notok_unknown;
skill->not_ok_hom = skillnotok_hom;
+ skill->not_ok_hom_unknown = skillnotok_hom_unknown;
skill->not_ok_mercenary = skillnotok_mercenary;
skill->chastle_mob_changetarget = skill_chastle_mob_changetarget;
skill->can_produce_mix = skill_can_produce_mix;
@@ -19498,6 +20577,7 @@ void skill_defaults(void) {
skill->sit_out = skill_sit_out;
skill->unitsetmapcell = skill_unitsetmapcell;
skill->unit_onplace_timer = skill_unit_onplace_timer;
+ skill->unit_onplace_timer_unknown = skill_unit_onplace_timer_unknown;
skill->unit_effect = skill_unit_effect;
skill->unit_timer_sub_onplace = skill_unit_timer_sub_onplace;
skill->unit_move_sub = skill_unit_move_sub;
@@ -19508,11 +20588,27 @@ void skill_defaults(void) {
skill->unit_timer = skill_unit_timer;
skill->unit_timer_sub = skill_unit_timer_sub;
skill->init_unit_layout = skill_init_unit_layout;
- skill->parse_row_skilldb = skill_parse_row_skilldb;
- skill->parse_row_requiredb = skill_parse_row_requiredb;
- skill->parse_row_castdb = skill_parse_row_castdb;
- skill->parse_row_castnodexdb = skill_parse_row_castnodexdb;
- skill->parse_row_unitdb = skill_parse_row_unitdb;
+ skill->init_unit_layout_unknown = skill_init_unit_layout_unknown;
+ /* Skill DB Libconfig */
+ skill->validate_hittype = skill_validate_hittype;
+ skill->validate_attacktype = skill_validate_attacktype;
+ skill->validate_element = skill_validate_element;
+ skill->validate_skilltype = skill_validate_skilltype;
+ skill->validate_skillinfo = skill_validate_skillinfo;
+ skill->validate_damagetype = skill_validate_damagetype;
+ skill->validate_castnodex = skill_validate_castnodex;
+ skill->validate_weapontype = skill_validate_weapontype;
+ skill->validate_ammotype = skill_validate_ammotype;
+ skill->validate_state = skill_validate_state;
+ skill->validate_item_requirements = skill_validate_item_requirements;
+ skill->validate_unit_target = skill_validate_unit_target;
+ skill->validate_unit_flag = skill_validate_unit_flag;
+ skill->validate_additional_fields = skill_validate_additional_fields;
+ skill->validate_skilldb = skill_validate_skilldb;
+ skill->read_skilldb = skill_read_skilldb;
+ skill->config_set_level = skill_config_set_level;
+ skill->level_set_value = skill_level_set_value;
+ /* */
skill->parse_row_producedb = skill_parse_row_producedb;
skill->parse_row_createarrowdb = skill_parse_row_createarrowdb;
skill->parse_row_abradb = skill_parse_row_abradb;
@@ -19569,4 +20665,7 @@ void skill_defaults(void) {
skill->get_requirement_off_unknown = skill_get_requirement_off_unknown;
skill->get_requirement_item_unknown = skill_get_requirement_item_unknown;
skill->get_requirement_unknown = skill_get_requirement_unknown;
+ skill->splash_target = skill_splash_target;
+ skill->check_npc_chaospanic = skill_check_npc_chaospanic;
+ skill->count_wos = skill_count_wos;
}