diff options
Diffstat (limited to 'src/map/skill.c')
-rw-r--r-- | src/map/skill.c | 2879 |
1 files changed, 2245 insertions, 634 deletions
diff --git a/src/map/skill.c b/src/map/skill.c index b4ce4e227..e187b7e8b 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2016 Hercules Dev Team + * Copyright (C) 2012-2017 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -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,9 @@ 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) +{ + nullpo_retr(BL_CHAR, 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.) @@ -92,7 +95,8 @@ static inline int splash_target(struct block_list* bl) { } /// Returns the id of the skill, or 0 if not found. -int skill_name2id(const char* name) { +int skill_name2id(const char* name) +{ if( name == NULL ) return 0; @@ -101,7 +105,8 @@ int skill_name2id(const char* name) { /// Maps skill ids to skill db offsets. /// Returns the skill's array index, or 0 (Unknown Skill). -int skill_get_index( uint16 skill_id ) { +int skill_get_index (uint16 skill_id) +{ // avoid ranges reserved for mapping guild/homun/mercenary skills if( (skill_id >= GD_SKILLRANGEMIN && skill_id <= GD_SKILLRANGEMAX) || (skill_id >= HM_SKILLRANGEMIN && skill_id <= HM_SKILLRANGEMAX) @@ -126,7 +131,7 @@ int skill_get_index( uint16 skill_id ) { skill_id = (1077) + skill_id - 2201; else if ( skill_id < 3036 ) // 2549 - 3000 are empty - 1020+57+348 skill_id = (1425) + skill_id - 3001; - else if ( skill_id < 5019 ) // 3036 - 5000 are empty - 1020+57+348+35 + else if ( skill_id < 5044 ) // 3036 - 5000 are empty - 1020+57+348+35 skill_id = (1460) + skill_id - 5001; else ShowWarning("skill_get_index: skill id '%d' is not being handled!\n",skill_id); @@ -213,19 +218,21 @@ int skill_get_fixed_cast( uint16 skill_id ,uint16 skill_lv ) { return 0; #endif } -int skill_tree_get_max(uint16 skill_id, int b_class) + +int skill_tree_get_max(uint16 skill_id, int class) { int i; - b_class = pc->class2idx(b_class); + int class_idx = pc->class2idx(class); - ARR_FIND( 0, MAX_SKILL_TREE, i, pc->skill_tree[b_class][i].id == 0 || pc->skill_tree[b_class][i].id == skill_id ); - if( i < MAX_SKILL_TREE && pc->skill_tree[b_class][i].id == skill_id ) - return pc->skill_tree[b_class][i].max; + ARR_FIND( 0, MAX_SKILL_TREE, i, pc->skill_tree[class_idx][i].id == 0 || pc->skill_tree[class_idx][i].id == skill_id ); + if( i < MAX_SKILL_TREE && pc->skill_tree[class_idx][i].id == skill_id ) + return pc->skill_tree[class_idx][i].max; else return skill->get_max(skill_id); } -int skill_get_casttype (uint16 skill_id) { +int skill_get_casttype(uint16 skill_id) +{ int inf = skill->get_inf(skill_id); if (inf&(INF_GROUND_SKILL)) return CAST_GROUND; @@ -241,8 +248,11 @@ int skill_get_casttype (uint16 skill_id) { return CAST_DAMAGE; } -int skill_get_casttype2 (uint16 index) { - int inf = skill->dbs->db[index].inf; +int skill_get_casttype2(uint16 index) +{ + int inf; + Assert_retr(CAST_NODAMAGE, index < MAX_SKILL_DB); + inf = skill->dbs->db[index].inf; if (inf&(INF_GROUND_SKILL)) return CAST_GROUND; if (inf&INF_SUPPORT_SKILL) @@ -258,7 +268,8 @@ int skill_get_casttype2 (uint16 index) { } //Returns actual skill range taking into account attack range and AC_OWL [Skotlex] -int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { +int skill_get_range2(struct block_list *bl, uint16 skill_id, uint16 skill_lv) +{ int range; struct map_session_data *sd = BL_CAST(BL_PC, bl); if( bl->type == BL_MOB && battle_config.mob_ai&0x400 ) @@ -292,7 +303,7 @@ int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { if (sd != NULL) range += pc->checkskill(sd, AC_VULTURE); else - range += 10; //Assume level 10? + range += battle->bc->mob_eye_range_bonus; break; // added to allow GS skills to be effected by the range of Snake Eyes [Reddozen] case GS_RAPIDSHOWER: @@ -303,7 +314,7 @@ int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { if (sd != NULL) range += pc->checkskill(sd, GS_SNAKEEYE); else - range += 10; //Assume level 10? + range += battle->bc->mob_eye_range_bonus; break; case NJ_KIRIKAGE: if (sd != NULL) @@ -354,7 +365,10 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk nullpo_ret(src); - switch( skill_id ) { + switch (skill_id) { + case SU_TUNABELLY: + hp = status_get_max_hp(target) * ((20 * skill_lv) - 10) / 100; + break; case BA_APPLEIDUN: #ifdef RENEWAL hp = 100+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery @@ -386,6 +400,11 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk hp += hp * skill2_lv * 2 / 100; else if (src->type == BL_HOM && (skill2_lv = homun->checkskill(BL_UCAST(BL_HOM, src), HLIF_BRAIN)) > 0) hp += hp * skill2_lv * 2 / 100; + if (sd != NULL && ((skill2_lv = pc->checkskill(sd, SU_POWEROFSEA)) > 0)) { + hp += hp * 10 / 100; + if (pc->checkskill(sd, SU_TUNABELLY) == 5 && pc->checkskill(sd, SU_TUNAPARTY) == 5 && pc->checkskill(sd, SU_BUNCHOFSHRIMP) == 5 && pc->checkskill(sd, SU_FRESHSHRIMP) == 5) + hp += hp * 20 / 100; + } break; } @@ -435,17 +454,19 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk // Making plagiarize check its own function [Aru] int can_copy (struct map_session_data *sd, uint16 skill_id, struct block_list* bl) { + nullpo_ret(sd); // Never copy NPC/Wedding Skills if (skill->get_inf2(skill_id)&(INF2_NPC_SKILL|INF2_WEDDING_SKILL)) return 0; - // High-class skills - if((skill_id >= LK_AURABLADE && skill_id <= ASC_CDP) || (skill_id >= ST_PRESERVE && skill_id <= CR_CULTIVATION)) - { - if(battle_config.copyskill_restrict == 2) + // Transcendent-class skills + if((skill_id >= LK_AURABLADE && skill_id <= ASC_CDP) || (skill_id >= ST_PRESERVE && skill_id <= CR_CULTIVATION)) { + if (battle_config.copyskill_restrict == 2) { return 0; - else if(battle_config.copyskill_restrict) - return (sd->status.class_ == JOB_STALKER); + } else if (battle_config.copyskill_restrict == 1) { + if ((sd->job & (MAPID_UPPERMASK | JOBL_UPPER)) != MAPID_STALKER) + return 0; + } } //Added so plagarize can't copy agi/bless if you're undead since it damages you @@ -454,8 +475,11 @@ int can_copy (struct map_session_data *sd, uint16 skill_id, struct block_list* b skill_id == MER_INCAGI || skill_id == MER_BLESSING)) return 0; - // Couldn't preserve 3rd Class skills except only when using Reproduce skill. [Jobbie] - if( !(sd->sc.data[SC__REPRODUCE]) && ((skill_id >= RK_ENCHANTBLADE && skill_id <= LG_OVERBRAND_PLUSATK) || (skill_id >= RL_GLITTERING_GREED && skill_id <= OB_AKAITSUKI) || (skill_id >= GC_DARKCROW && skill_id <= NC_MAGMA_ERUPTION_DOTDAMAGE))) + // Couldn't preserve 3rd Class/Summoner skills except only when using Reproduce skill. [Jobbie] + if (!(sd->sc.data[SC__REPRODUCE]) && + ((skill_id >= RK_ENCHANTBLADE && skill_id <= LG_OVERBRAND_PLUSATK) || + (skill_id >= RL_GLITTERING_GREED && skill_id <= OB_AKAITSUKI) || + (skill_id >= GC_DARKCROW && skill_id <= SU_FRESHSHRIMP))) return 0; // Reproduce will only copy skills according on the list. [Jobbie] else if( sd->sc.data[SC__REPRODUCE] && !skill->dbs->reproduce_db[skill->get_index(skill_id)] ) @@ -545,6 +569,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_THERE_ARE_NPC_AROUND,0); return 1; } + FALLTHROUGH case MC_IDENTIFY: return 0; // always allowed case WZ_ICEWALL: @@ -579,11 +604,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 +644,21 @@ 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) +{ + nullpo_retr(1, 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); @@ -629,10 +672,12 @@ int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md) return skill->not_ok(skill_id, md->master); } -struct s_skill_unit_layout* skill_get_unit_layout (uint16 skill_id, uint16 skill_lv, struct block_list* src, int x, int y) { +struct s_skill_unit_layout* skill_get_unit_layout(uint16 skill_id, uint16 skill_lv, struct block_list* src, int x, int y) +{ int pos = skill->get_unit_layout_type(skill_id,skill_lv); uint8 dir; + nullpo_retr(&skill->dbs->unit_layout[0], src); if (pos < -1 || pos >= MAX_SKILL_UNIT_LAYOUT) { ShowError("skill_get_unit_layout: unsupported layout type %d for skill %d (level %d)\n", pos, skill_id, skill_lv); pos = cap_value(pos, 0, MAX_SQUARE_LAYOUT); // cap to nearest square layout @@ -869,6 +914,10 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 break; #endif + case WZ_HEAVENDRIVE: + status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER); + break; + case WZ_STORMGUST: /** * Storm Gust counter was dropped in renewal @@ -1102,8 +1151,8 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 break; case TK_JUMPKICK: - if( dstsd && dstsd->class_ != MAPID_SOUL_LINKER && !tsc->data[SC_PRESERVE] ) - {// debuff the following statuses + if (dstsd != NULL && (dstsd->job & MAPID_UPPERMASK) != MAPID_SOUL_LINKER && tsc->data[SC_PRESERVE] == NULL) { + // debuff the following statuses status_change_end(bl, SC_SOULLINK, INVALID_TIMER); status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); status_change_end(bl, SC_KAITE, INVALID_TIMER); @@ -1382,6 +1431,25 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case MH_XENO_SLASHER: sc_start2(src, bl, SC_BLOODING, 10 * skill_lv, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); break; + /** + * Summoner + */ + case SU_SCRATCH: + sc_start2(src, bl, SC_BLOODING, (skill_lv * 3), skill_lv, src->id, skill->get_time(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_SV_STEMSPEAR: + sc_start2(src, bl, SC_BLOODING, 10, skill_lv, src->id, skill->get_time(skill_id, skill_lv)); + break; + case SU_CN_METEOR: + sc_start(src, bl, SC_CURSE, 10, skill_lv, skill->get_time2(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_SCAROFTAROU: + sc_start(src, bl, SC_STUN, 10, skill_lv, skill->get_time2(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_LUNATICCARROTBEAT: + if (skill->area_temp[3] == 1) + sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time(skill_id, skill_lv)); // TODO: What's the chance/time? + break; default: skill->additional_effect_unknown(src, bl, &skill_id, &skill_lv, &attack_type, &dmg_lv, &tick); break; @@ -1546,17 +1614,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 +1742,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; } @@ -1789,7 +1843,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b break; } - if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR + if (sd != NULL && (sd->job & MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && rnd()%10000 < battle_config.sg_miracle_skill_ratio) // SG_MIRACLE [Komurka] sc_start(src,src,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); @@ -1898,17 +1952,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 +2049,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 +2075,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); } } @@ -2041,7 +2085,8 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in return where; //Return list of pieces broken. } -int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time) { +int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time) +{ struct status_change *sc; const int pos[5] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC}; const enum sc_type sc_atk[5] = {SC_NOEQUIPWEAPON, SC_NOEQUIPSHIELD, SC_NOEQUIPARMOR, SC_NOEQUIPHELM, SC__STRIPACCESSARY}; @@ -2067,21 +2112,25 @@ 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; + struct status_change *tsc = status->get_sc(target); nullpo_ret(src); if (src != target && map->list[src->m].flag.noknockback) return 0; // No knocking + + nullpo_ret(target); if (count == 0) return 0; // Actual knockback distance is 0. @@ -2089,7 +2138,7 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in case BL_MOB: { const struct mob_data *md = BL_UCCAST(BL_MOB, target); - if (md->class_ == MOBID_EMPELIUM) + if (md->status.mode&MD_NOKNOCKBACK) return 0; if (src != target && is_boss(target)) // Bosses can't be knocked-back return 0; @@ -2122,6 +2171,9 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in dy = -diry[dir]; } + if (tsc != NULL && tsc->data[SC_SU_STOOP]) // Any knockback will cancel it. + status_change_end(target, SC_SU_STOOP, INVALID_TIMER); + return unit->blown(target, dx, dy, count, flag); // send over the proper flag } @@ -2132,10 +2184,12 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in 1 - Regular reflection (Maya) 2 - SL_KAITE reflection */ -int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) { +int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) +{ struct status_change *sc = status->get_sc(bl); struct map_session_data* sd = BL_CAST(BL_PC, bl); + nullpo_ret(src); if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability return 0; @@ -2179,7 +2233,8 @@ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) * client (causes player characters to not scream skill name) * flag&0x4000 - Return 0 if damage was reflected *-------------------------------------------------------------------------*/ -int skill_attack(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 skill_attack(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) +{ struct Damage dmg; struct status_data *sstatus, *tstatus; struct status_change *sc; @@ -2375,7 +2430,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case TK_STORMKICK: case TK_DOWNKICK: case TK_COUNTER: - if (pc->famerank(sd->status.char_id,MAPID_TAEKWON)) {//Extend combo time. + if (pc->fame_rank(sd->status.char_id, RANKTYPE_TAEKWON) > 0) { //Extend combo time. sce->val1 = skill_id; //Update combo-skill sce->val3 = skill_id; if( sce->timer != INVALID_TIMER ) @@ -2493,6 +2548,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case KO_MUCHANAGE: if( dmg.dmg_lv == ATK_FLEE ) break; + FALLTHROUGH case WL_SOULEXPANSION: case WL_COMET: case NJ_HUUMA: @@ -2505,6 +2561,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case LG_OVERBRAND: /* Fall through */ dmg.amotion = status_get_amotion(src) * 2; + FALLTHROUGH case LG_OVERBRAND_PLUSATK: dmg.dmotion = clif->skill_damage(dsrc,bl,tick,status_get_amotion(src),dmg.dmotion,damage,dmg.div_,skill_id,-1,BDT_SPLASH); break; @@ -2563,6 +2620,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr dmg.dmotion = clif->skill_damage(src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, (flag&SD_LEVEL) ? -1 : skill_lv, BDT_SPLASH); if( dsrc != src ) // avoid damage display redundancy break; + FALLTHROUGH case HT_LANDMINE: dmg.dmotion = clif->skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, -1, type); break; @@ -2575,6 +2633,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case AB_DUPLELIGHT_MELEE: case AB_DUPLELIGHT_MAGIC: dmg.amotion = 300;/* makes the damage value not overlap with previous damage (when displayed by the client) */ + FALLTHROUGH default: skill->attack_display_unknown(&attack_type, src, dsrc, bl, &skill_id, &skill_lv, &tick, &flag, &type, &dmg, &damage); break; @@ -2833,7 +2892,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )// Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] rate = 100 - tstatus->int_ * 4 / 5; sc_start(src, bl,ssc->data[SC_POISONINGWEAPON]->val2,rate,ssc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); - status_change_end(src,SC_POISONINGWEAPON,-1); + status_change_end(src, SC_POISONINGWEAPON, INVALID_TIMER); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } } @@ -2870,15 +2929,27 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr return (int)cap_value(damage,INT_MIN,INT_MAX); } -void skill_attack_combo1_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, struct status_change_entry *sce, int *combo) { +void skill_attack_combo1_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, struct status_change_entry *sce, int *combo) +{ if (src == dsrc) // Ground skills are exceptions. [Inkfish] status_change_end(src, SC_COMBOATTACK, INVALID_TIMER); } -void skill_attack_combo2_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 *combo) { +void skill_attack_combo2_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 *combo) +{ } -void skill_attack_display_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) { +void skill_attack_display_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) +{ + nullpo_retv(bl); + nullpo_retv(dmg); + nullpo_retv(tick); + nullpo_retv(flag); + nullpo_retv(damage); + nullpo_retv(skill_id); + nullpo_retv(skill_lv); + nullpo_retv(type); + if (*flag & SD_ANIMATION && dmg->div_ < 2) //Disabling skill animation doesn't works on multi-hit. *type = BDT_SPLASH; if (bl->type == BL_SKILL) { @@ -2889,15 +2960,24 @@ void skill_attack_display_unknown(int *attack_type, struct block_list* src, stru dmg->dmotion = clif->skill_damage(dsrc, bl, *tick, dmg->amotion, dmg->dmotion, *damage, dmg->div_, *skill_id, (*flag & SD_LEVEL) ? -1 : *skill_lv, *type); } -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; +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) +{ + nullpo_ret(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; +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; } -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) { +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) +{ + nullpo_retv(bl); + nullpo_retv(dmg); + nullpo_retv(dir); + nullpo_retv(damage); + skill->blown(dsrc, bl, dmg->blewcount, *dir, 0x0); if (!dmg->blewcount && bl->type == BL_SKILL && *damage > 0){ struct skill_unit *su = BL_UCAST(BL_SKILL, bl); @@ -2906,7 +2986,8 @@ void skill_attack_blow_unknown(int *attack_type, struct block_list* src, struct } } -void skill_attack_post_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) { +void skill_attack_post_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) +{ } /*========================================== @@ -2914,7 +2995,8 @@ void skill_attack_post_unknown(int *attack_type, struct block_list* src, struct * Checking bl battle flag and display damage * then call func with source,target,skill_id,skill_lv,tick,flag *------------------------------------------*/ -int skill_area_sub(struct block_list *bl, va_list ap) { +int skill_area_sub(struct block_list *bl, va_list ap) +{ struct block_list *src; uint16 skill_id,skill_lv; int flag; @@ -2965,6 +3047,7 @@ int skill_check_unit_range_sub(struct block_list *bl, va_list ap) case AL_PNEUMA: if(g_skill_id == SA_LANDPROTECTOR) break; + FALLTHROUGH case MG_SAFETYWALL: case MH_STEINWAND: case SC_MAELSTROM: @@ -3387,6 +3470,7 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { skill->blown(src,target,skill->get_blewcount(skl->skill_id, skl->skill_lv), -1, 0x0 ); break; } + FALLTHROUGH } default: skill->timerskill_target_unknown(tid, tick, src, target, ud, skl); @@ -3397,7 +3481,8 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { break; switch( skl->skill_id ) { case WZ_METEOR: - if( skl->type >= 0 ) { + case SU_CN_METEOR: + if (skl->type >= 0) { int x = skl->type>>16, y = skl->type&0xFFFF; if( path->search_long(NULL, src, src->m, src->x, src->y, x, y, CELL_CHKWALL) ) skill->unitsetting(src,skl->skill_id,skl->skill_lv,x,y,skl->flag); @@ -3413,6 +3498,7 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { map->foreachinarea(skill->cell_overlap,src->m,skl->x-i,skl->y-i,skl->x+i,skl->y+i,BL_SKILL,skl->skill_id,&dummy,src); } + FALLTHROUGH // fall through ... case WL_EARTHSTRAIN: skill->unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,(skl->type<<16)|skl->flag); @@ -3440,6 +3526,7 @@ bool skill_timerskill_dead_unknown(struct block_list *src, struct unit_data *ud, void skill_timerskill_target_unknown(int tid, int64 tick, struct block_list *src, struct block_list *target, struct unit_data *ud, struct skill_timerskill *skl) { + nullpo_retv(skl); skill->attack(skl->type, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag); } @@ -3450,7 +3537,8 @@ void skill_timerskill_notarget_unknown(int tid, int64 tick, struct block_list *s /*========================================== * *------------------------------------------*/ -int skill_addtimerskill(struct block_list *src, int64 tick, int target, int x,int y, uint16 skill_id, uint16 skill_lv, int type, int flag) { +int skill_addtimerskill(struct block_list *src, int64 tick, int target, int x,int y, uint16 skill_id, uint16 skill_lv, int type, int flag) +{ int i; struct unit_data *ud; nullpo_retr(1, src); @@ -3554,11 +3642,28 @@ 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: + nullpo_retv(bl); + 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; + } +} + /*========================================== * * *------------------------------------------*/ -int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { +int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) +{ struct map_session_data *sd = NULL; struct status_data *tstatus; struct status_change *sc; @@ -3744,7 +3849,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 +3860,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 +3896,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 +3907,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; @@ -3896,11 +4001,22 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; - //Splash attack skills. + case SU_BITE: + skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + if (status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); + break; + + case SU_PICKYPECK: + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + + // Splash attack skills. case AS_GRIMTOOTH: case MC_CARTREVOLUTION: case NPC_SPLASHATTACK: flag |= SD_PREAMBLE; // a fake packet will be sent for the first target to be hit + FALLTHROUGH case AS_SPLASHER: case HT_BLITZBEAT: case AC_SHOWER: @@ -3948,7 +4064,9 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case KO_BAKURETSU: case GN_ILLUSIONDOPING: case MH_XENO_SLASHER: - if( flag&1 ) {//Recursive invocation + case SU_SCRATCH: + case SU_LUNATICCARROTBEAT: + if (flag&1) { //Recursive invocation // skill->area_temp[0] holds number of targets in area // skill->area_temp[1] holds the id of the original target // skill->area_temp[2] counts how many targets have already been processed @@ -3963,15 +4081,19 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 break; heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); - if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) { + if (skill_id == NPC_VAMPIRE_GIFT && heal > 0) { clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); status->heal(src,heal,0,0); } + if (skill_id == SU_SCRATCH && status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); } else { switch ( skill_id ) { case NJ_BAKUENRYU: case LG_EARTHDRIVE: case GN_CARTCANNON: + case SU_SCRATCH: + case SU_LUNATICCARROTBEAT: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case SR_TIGERCANNON: @@ -3990,13 +4112,19 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->area_temp[0] = 0; skill->area_temp[1] = bl->id; skill->area_temp[2] = 0; - if( skill_id == WL_CRIMSONROCK ) { + if (skill_id == WL_CRIMSONROCK) { skill->area_temp[4] = bl->x; skill->area_temp[5] = bl->y; } + if (skill_id == SU_LUNATICCARROTBEAT) { + skill->area_temp[3] = 0; + } - if( skill_id == NC_VULCANARM ) - if (sd) pc->overheat(sd,1); + if (skill_id == NC_VULCANARM) { + if (sd != NULL) { + pc->overheat(sd,1); + } + } // if skill damage should be split among targets, count them //SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets @@ -4005,7 +4133,16 @@ 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); + + if (sd && skill_id == SU_LUNATICCARROTBEAT) { + short item_idx = pc->search_inventory(sd, ITEMID_CARROT); + + if (item_idx >= 0) { + pc->delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME); + skill->area_temp[3] = 1; + } + } } break; @@ -4086,9 +4223,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); @@ -4281,6 +4418,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if( (tsc = status->get_sc(bl)) && tsc->data[SC_HIDING] ) break; } + FALLTHROUGH case HVAN_EXPLOSION: if (src != bl) skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); @@ -4489,18 +4627,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); @@ -4549,6 +4676,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 } break; } + FALLTHROUGH case RA_WUGBITE: if( path->search(NULL,src,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); @@ -4572,7 +4700,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if( !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = sg->item_id?sg->item_id:ITEMID_TRAP; + item_tmp.nameid = sg->item_id ? sg->item_id : ITEMID_BOOBY_TRAP; item_tmp.identify = 1; if( item_tmp.nameid ) map->addflooritem(bl, &item_tmp, 1, bl->m, bl->x, bl->y, 0, 0, 0, 0); @@ -4589,7 +4717,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 +4735,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 +4794,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 +4931,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; @@ -4824,6 +4952,15 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; + case SU_SV_STEMSPEAR: + skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + if (status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, (skill_id == SU_SV_STEMSPEAR) ? BF_MAGIC : BF_WEAPON, flag); + break; + case SU_SCAROFTAROU: + sc_start(src, bl, status->skill2sc(skill_id), 10, skill_lv, skill->get_time(skill_id, skill_lv)); // TODO: What's the activation chance for the effect? + break; + case 0:/* no skill - basic/normal attack */ if(sd) { if (flag & 3){ @@ -4869,6 +5006,10 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 bool skill_castend_damage_id_unknown(struct block_list* src, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, struct status_data *tstatus, struct status_change *sc) { + nullpo_retr(true, skill_id); + nullpo_retr(true, skill_lv); + nullpo_retr(true, tick); + nullpo_retr(true, tstatus); ShowWarning("skill_castend_damage_id: Unknown skill used:%d\n", *skill_id); clif->skill_damage(src, bl, *tick, status_get_amotion(src), tstatus->dmotion, 0, abs(skill->get_num(*skill_id, *skill_lv)), @@ -4880,7 +5021,8 @@ bool skill_castend_damage_id_unknown(struct block_list* src, struct block_list * /*========================================== * *------------------------------------------*/ -int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { +int skill_castend_id(int tid, int64 tick, int id, intptr_t data) +{ struct block_list *target, *src; struct map_session_data *sd; struct mob_data *md; @@ -4917,12 +5059,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; } @@ -4957,6 +5098,8 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { ud->skilltimer=tid; return skill->castend_pos(tid,tick,id,data); case GN_WALLOFTHORN: + case SU_CN_POWDERING: + case SU_SV_ROOTTWIST: ud->skillx = target->x; ud->skilly = target->y; ud->skilltimer = tid; @@ -5123,7 +5266,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { unit->set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); if(battle_config.skill_log && battle_config.skill_log&src->type) - ShowInfo("Type %d, ID %d skill castend id [id =%d, lv=%d, target ID %d]\n", + ShowInfo("Type %u, ID %d skill castend id [id =%d, lv=%d, target ID %d]\n", src->type, src->id, ud->skill_id, ud->skill_lv, target->id); map->freeblock_lock(); @@ -5219,13 +5362,14 @@ 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; } /*========================================== * *------------------------------------------*/ -int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { +int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) +{ struct map_session_data *sd, *dstsd; struct mob_data *md, *dstmd; struct homun_data *hd; @@ -5302,6 +5446,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ; break ; } + FALLTHROUGH case AL_HEAL: /** @@ -5401,12 +5546,12 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin type = status->skill2sc(skill_id); tsc = status->get_sc(bl); - tsce = (tsc && type != -1)?tsc->data[type]:NULL; + tsce = (tsc != NULL && type != SC_NONE) ? tsc->data[type] : NULL; - if (src!=bl && type > -1 && - (element = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL && - skill->get_inf(skill_id) != INF_SUPPORT_SKILL && - battle->attr_fix(NULL, NULL, 100, element, tstatus->def_ele, tstatus->ele_lv) <= 0) + if (src != bl && type > SC_NONE + && (element = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL + && skill->get_inf(skill_id) != INF_SUPPORT_SKILL + && battle->attr_fix(NULL, NULL, 100, element, tstatus->def_ele, tstatus->ele_lv) <= 0) return 1; //Skills that cause an status should be blocked if the target element blocks its element. map->freeblock_lock(); @@ -5417,6 +5562,10 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin * Arch Bishop **/ case AB_HIGHNESSHEAL: + /** + * Summoner + */ + case SU_TUNABELLY: { int heal = skill->calc_heal(src, bl, (skill_id == AB_HIGHNESSHEAL)?AL_HEAL:skill_id, (skill_id == AB_HIGHNESSHEAL)?10:skill_lv, true); int heal_get_jobexp; @@ -5427,7 +5576,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (status->isimmune(bl) || (dstmd != NULL && (dstmd->class_ == MOBID_EMPELIUM || mob_is_battleground(dstmd)))) heal = 0; - if (sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0) + if (sd != NULL && dstsd != NULL && sd->status.partner_id == dstsd->status.char_id && (sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0) heal = heal * 2; if (tsc && tsc->count) @@ -5446,6 +5595,9 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin else if (tsc->data[SC_BERSERK]) heal = 0; //Needed so that it actually displays 0 when healing. } + if (skill_id == AL_HEAL) { + status_change_end(bl, SC_BITESCAR, INVALID_TIMER); + } clif->skill_nodamage (src, bl, skill_id, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) heal = ~heal + 1; @@ -5455,7 +5607,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 +5683,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); } } } @@ -5715,7 +5867,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case CR_PROVIDENCE: if(sd && dstsd){ //Check they are not another crusader [Skotlex] - if ((dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER) { + if ((dstsd->job & MAPID_UPPERMASK) == MAPID_CRUSADER) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); map->freeblock_unlock(); return 1; @@ -5729,7 +5881,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin { struct status_change* sc = status->get_sc(src); - if( sd && dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex ) { + if (sd != NULL && dstsd != NULL && (dstsd->job & MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex) { // Cannot cast on another bard/dancer-type class of the same gender as caster clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); map->freeblock_unlock(); @@ -5825,6 +5977,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case PR_KYRIE: case MER_KYRIE: + case SU_TUNAPARTY: clif->skill_nodamage(bl, bl, skill_id, -1, sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; @@ -5941,9 +6094,18 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case RK_ABUNDANCE: case RK_CRUSHSTRIKE: case ALL_ODINS_POWER: + case SU_FRESHSHRIMP: + case SU_ARCLOUSEDASH: clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; + // Works just like the above list of skills, except animation caused by + // status must trigger AFTER the skill cast animation or it will cancel + // out the status's animation. + case SU_STOOP: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + break; case KN_AUTOCOUNTER: sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); skill->addtimerskill(src, tick + 100, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); @@ -6141,7 +6303,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if( lv > battle_config.devotion_level_difference || // Level difference requeriments (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || // Cannot Devote a player devoted from another source (skill_id == ML_DEVOTION && (!mer || mer != dstsd->md)) || // Mercenary only can devote owner - (dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER || // Crusader Cannot be devoted + (dstsd->job & MAPID_UPPERMASK) == MAPID_CRUSADER || // Crusader Cannot be devoted (dstsd->sc.data[SC_HELLPOWER])) // Players affected by SC_HELLPOWERR cannot be devoted. { if( sd ) @@ -6168,7 +6330,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sd->devotion[i] = bl->id; } - else + else if (mer != NULL) mer->devotion_flag = 1; // Mercenary Devoting Owner clif->skill_nodamage(src, bl, skill_id, skill_lv, @@ -6194,7 +6356,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; case MO_KITRANSLATION: - if(dstsd && ((dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER || (dstsd->class_&MAPID_UPPERMASK)!=MAPID_REBELLION)) { + if (dstsd != NULL && (dstsd->job & MAPID_BASEMASK) != MAPID_GUNSLINGER) { pc->addspiritball(dstsd,skill->get_time(skill_id,skill_lv),5); } break; @@ -6210,10 +6372,10 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case MO_ABSORBSPIRITS: { int sp = 0; - if ( dstsd && dstsd->spiritball - && (sd == dstsd || map_flag_vs(src->m) || (sd && sd->duel_group && sd->duel_group == dstsd->duel_group)) - && ((dstsd->class_&MAPID_BASEMASK) != MAPID_GUNSLINGER || (dstsd->class_&MAPID_UPPERMASK) != MAPID_REBELLION) - ) { + if (dstsd != NULL && dstsd->spiritball != 0 + && (sd == dstsd || map_flag_vs(src->m) || (sd && sd->duel_group && sd->duel_group == dstsd->duel_group)) + && (dstsd->job & MAPID_BASEMASK) != MAPID_GUNSLINGER + ) { // split the if for readability, and included gunslingers in the check so that their coins cannot be removed [Reddozen] sp = dstsd->spiritball * 7; pc->delspiritball(dstsd, dstsd->spiritball, 0); @@ -6259,7 +6421,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 +6440,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 +6486,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 +6500,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); @@ -6414,7 +6576,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (sd) { if (!dstsd || !( (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SOULLINKER) - || (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER + || (dstsd->job & MAPID_UPPERMASK) == MAPID_SOUL_LINKER || dstsd->status.char_id == sd->status.char_id || dstsd->status.char_id == sd->status.partner_id || dstsd->status.char_id == sd->status.child @@ -6540,8 +6702,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case RG_STEALCOIN: if(sd) { - int amount = pc->steal_coin(sd, bl); - if( amount > 0 ) { + int amount = pc->steal_coin(sd, bl, skill_lv); + if (amount > 0 && dstmd != NULL) { dstmd->state.provoke_flag = src->id; mob->target(dstmd, src, skill->get_range2(src, skill_id, skill_lv)); clif->skill_nodamage(src, bl, skill_id, amount, 1); @@ -6598,7 +6760,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin status_change_end(bl, SC_SILENCE, INVALID_TIMER); status_change_end(bl, SC_BLIND, INVALID_TIMER); status_change_end(bl, SC_CONFUSION, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(bl, SC_BITESCAR, INVALID_TIMER); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); break; case TF_DETOXIFY: @@ -6892,7 +7055,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; @@ -7048,7 +7211,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) + if ((dstsd != NULL && (dstsd->job & MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends against dispel. || (dstsd && pc_ismadogear(dstsd)) || rnd()%100 >= 50+10*skill_lv ) @@ -7297,7 +7460,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case NPC_REBIRTH: if( md && md->state.rebirth ) break; // only works once - sc_start(src,bl,type,100,skill_lv,-1); + sc_start(src, bl, type, 100, skill_lv, INFINITE_DURATION); break; case NPC_DARKBLESSING: @@ -7307,8 +7470,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case NPC_LICK: status_zap(bl, 0, 100); - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(src,bl,type,(skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv))); + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(src, bl, type, (skill_lv * 20), skill_lv, skill->get_time2(skill_id, skill_lv))); break; case NPC_SUICIDE: @@ -7505,7 +7668,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = skill->dbs->db[su->group->skill_id].itemid[i]; item_tmp.identify = 1; - if (item_tmp.nameid && (success=pc->additem(sd,&item_tmp,skill->dbs->db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) != 0) { + if (item_tmp.nameid && (success=pc->additem(sd,&item_tmp,skill->dbs->db[su->group->skill_id].amount[i],LOG_TYPE_SKILL)) != 0) { clif->additem(sd,0,0,success); map->addflooritem(&sd->bl, &item_tmp, skill->dbs->db[su->group->skill_id].amount[i], sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } @@ -7515,9 +7678,9 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin // get back 1 trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = su->group->item_id?su->group->item_id:ITEMID_TRAP; + item_tmp.nameid = su->group->item_id ? su->group->item_id : ITEMID_BOOBY_TRAP; item_tmp.identify = 1; - if (item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) != 0) { + if (item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SKILL)) != 0) { clif->additem(sd,0,0,flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); } @@ -7541,6 +7704,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin // remove trap should be used instead break; // otherwise fall through to below + FALLTHROUGH case UNT_BLASTMINE: case UNT_SKIDTRAP: case UNT_LANDMINE: @@ -7578,7 +7742,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start4(src,bl,type,100,skill_lv,skill_id,src->id,skill->get_time(skill_id,skill_lv),1000)); #ifndef RENEWAL - if (sd) skill->blockpc_start (sd, skill_id, skill->get_time(skill_id, skill_lv)+3000); + if (sd) + skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv) + 3000); #endif break; @@ -7839,7 +8004,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case SL_SUPERNOVICE: case SL_WIZARD: //NOTE: here, 'type' has the value of the associated MAPID, not of the SC_SOULLINK constant. - if (sd && !(dstsd && (dstsd->class_&MAPID_UPPERMASK) == type)) { + if (sd != NULL && !(dstsd != NULL && (dstsd->job & MAPID_UPPERMASK) == type)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -7855,7 +8020,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sc_start(src,src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; case SL_HIGH: - if (sd && !(dstsd && (dstsd->class_&JOBL_UPPER) && !(dstsd->class_&JOBL_2) && dstsd->status.base_level < 70)) { + if (sd != NULL && !(dstsd != NULL && (dstsd->job & JOBL_UPPER) != 0 && (dstsd->job & JOBL_2) == 0 && dstsd->status.base_level < 70)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -8016,8 +8181,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin int x,y; x = src->x; y = src->y; - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); + if (hd) { +#ifdef RENEWAL + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); +#else + skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id, skill_lv)); +#endif + } + if (unit->movepos(src,bl->x,bl->y,0,0)) { clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homun @@ -8390,7 +8561,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case AB_ANCILLA: if( sd ) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1); + skill->produce_mix(sd, skill_id, ITEMID_ANSILA, 0, 0, 0, 1); } break; @@ -8508,7 +8679,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); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 60 + 8 * skill_lv) { + if ((dstsd != NULL && (dstsd->job & MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 60 + 8 * skill_lv) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; @@ -8518,9 +8689,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin for(i = 0; i < SC_MAX; i++) { if ( !tsc->data[i] ) continue; - if( SC_COMMON_MAX > i ) - if ( status->get_sc_type(i)&SC_NO_CLEARANCE ) - continue; + if (status->get_sc_type(i)&SC_NO_CLEARANCE) + continue; switch (i) { case SC_ASSUMPTIO: if( bl->type == BL_MOB ) @@ -8648,7 +8818,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; } - sc_start(src, bl, SC_STOP, 100, skill_lv, INVALID_TIMER); //Can't move while selecting a spellbook. + sc_start(src, bl, SC_STOP, 100, skill_lv, INFINITE_DURATION); //Can't move while selecting a spellbook. clif->spellbook_list(sd); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } @@ -8736,7 +8906,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); } @@ -8777,7 +8947,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if( sd ) { int idx1 = skill->get_index(sd->reproduceskill_id), idx2 = skill->get_index(sd->cloneskill_id); if( sd->status.skill[idx1].id || sd->status.skill[idx2].id ) { - sc_start(src,src,SC_STOP,100,skill_lv,-1);// The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] + sc_start(src, src, SC_STOP, 100, skill_lv, INFINITE_DURATION); // The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] clif->autoshadowspell_list(sd); clif->skill_nodamage(src,bl,skill_id,1,1); } @@ -8826,9 +8996,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))); @@ -8859,6 +9029,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case LG_TRAMPLE: clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); map->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); + status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER); break; case LG_REFLECTDAMAGE: @@ -8894,7 +9065,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin splashrange = 3; switch( opt ) { case 1: - sc_start(src,bl,SC_SHIELDSPELL_DEF,100,opt,INVALID_TIMER); //Splash AoE ATK + sc_start(src, bl, SC_SHIELDSPELL_DEF, 100, opt, INFINITE_DURATION); // Splash AoE ATK clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); map->foreachinrange(skill->area_sub,src,splashrange,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); status_change_end(bl,SC_SHIELDSPELL_DEF,INVALID_TIMER); @@ -8921,7 +9092,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin splashrange = 3; switch( opt ) { case 1: - sc_start(src,bl,SC_SHIELDSPELL_MDEF,100,opt,INVALID_TIMER); //Splash AoE MATK + sc_start(src, bl, SC_SHIELDSPELL_MDEF, 100, opt, INFINITE_DURATION); // Splash AoE MATK clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); map->foreachinrange(skill->area_sub,src,splashrange,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); status_change_end(bl,SC_SHIELDSPELL_MDEF,INVALID_TIMER); @@ -8958,7 +9129,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sc_start(src,bl,SC_SCRESIST,100,rate,shield->refine * 30000)); break; case 3: - sc_start(src,bl,SC_SHIELDSPELL_REF,100,opt,INVALID_TIMER); //HP Recovery + sc_start(src, bl, SC_SHIELDSPELL_REF, 100, opt, INFINITE_DURATION); // HP Recovery val = sstatus->max_hp * ((status->get_lv(src) / 10) + (shield->refine + 1)) / 100; status->heal(bl, val, 0, 2); status_change_end(bl,SC_SHIELDSPELL_REF,INVALID_TIMER); @@ -9065,8 +9236,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case SR_ASSIMILATEPOWER: if( flag&1 ) { int sp = 0; - if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) - { + if (dstsd != NULL && dstsd->spiritball != 0 && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->job & MAPID_BASEMASK) != MAPID_GUNSLINGER) { sp = dstsd->spiritball; //1%sp per spiritball. pc->delspiritball(dstsd, dstsd->spiritball, 0); status_percent_heal(src, 0, sp); @@ -9077,14 +9247,14 @@ 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; case SR_POWERVELOCITY: if( !dstsd ) break; - if ( sd && (dstsd->class_&MAPID_BASEMASK) != MAPID_GUNSLINGER ) { + if (sd != NULL && (dstsd->job & MAPID_BASEMASK) != MAPID_GUNSLINGER) { int i, max = pc->getmaxspiritball(dstsd, 5); for ( i = 0; i < max; i++ ) { pc->addspiritball(dstsd, skill->get_time(MO_CALLSPIRITS, 1), max); @@ -9281,7 +9451,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin improv_skill_lv = 4 + skill_lv; clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); - if (sd == NULL) { + if (sd != NULL) { sd->state.abra_flag = 2; sd->skillitem = improv_skill_id; sd->skillitemlv = improv_skill_lv; @@ -9388,6 +9558,25 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, 0, 1, skill_id, -2, BDT_SKILL); break; + case SU_HIDE: + if (tsce != NULL) { + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_change_end(bl, type, INVALID_TIMER); + map->freeblock_unlock(); + return 0; + } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + break; + + case SU_BUNCHOFSHRIMP: + if (sd == NULL || sd->status.party_id == 0 || flag&1) { + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + } else if (sd != NULL) { + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + } + break; + case GM_SANDMAN: if( tsc ) { if( tsc->opt1 == OPT1_SLEEP ) @@ -9431,7 +9620,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case SO_EL_CONTROL: if( sd ) { - int mode = EL_MODE_PASSIVE; // Standard mode. + uint32 mode = EL_MODE_PASSIVE; // Standard mode. if( !sd->ed ) break; @@ -9443,7 +9632,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case 2: mode = EL_MODE_ASSIST; break; case 3: mode = EL_MODE_AGGRESSIVE; break; } - if( !elemental->change_mode(sd->ed,mode) ) { + if (!elemental->change_mode(sd->ed, mode)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -9668,7 +9857,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if(sd) { struct mob_data *summon_md; - summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE); + summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE); if( summon_md ) { summon_md->master_id = src->id; summon_md->special_state.ai = AI_ZANZOU; @@ -9769,7 +9958,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; @@ -9794,6 +9983,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin SC_MANDRAGORA, SC_HARMONIZE, SC_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION }; int heal; + if (hd == NULL) + break; if(tsc){ int i; for (i = 0; i < ARRAYLENGTH(scs); i++) { @@ -9848,7 +10039,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; for (i = 0; i < summons[skill_lv-1].quantity; i++) { - struct mob_data *summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), + struct mob_data *summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), summons[skill_lv-1].mob_id, "", SZ_SMALL, AI_ATTACK); if (summon_md != NULL) { summon_md->master_id = src->id; @@ -9900,21 +10091,23 @@ 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) { + nullpo_retr(true, skill_id); + nullpo_retr(true, skill_lv); ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n", *skill_id); clif->skill_nodamage(src, bl, *skill_id, *skill_lv, 1); map->freeblock_unlock(); @@ -9931,6 +10124,7 @@ int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) struct unit_data *ud = unit->bl2ud(src); struct mob_data *md; + nullpo_ret(src); nullpo_ret(ud); sd = BL_CAST(BL_PC , src); @@ -9948,7 +10142,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); @@ -10023,7 +10217,7 @@ int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) } if(battle_config.skill_log && battle_config.skill_log&src->type) - ShowInfo("Type %d, ID %d skill castend pos [id =%d, lv=%d, (%d,%d)]\n", + ShowInfo("Type %u, ID %d skill castend pos [id =%d, lv=%d, (%d,%d)]\n", src->type, src->id, ud->skill_id, ud->skill_lv, ud->skillx, ud->skilly); if (ud->walktimer != INVALID_TIMER) @@ -10084,7 +10278,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,9 +10291,13 @@ 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*); + nullpo_retr(1, bl); + nullpo_retr(1, src); if( src->id != bl->id ) { return 1; } @@ -10109,8 +10307,10 @@ static int skill_count_wos(struct block_list *bl,va_list ap) { /*========================================== * *------------------------------------------*/ -int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *mapname) { +int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *mapname) +{ nullpo_ret(sd); + nullpo_ret(mapname); //Simplify skill_failed code. #define skill_failed(sd) ( (sd)->menuskill_id = (sd)->menuskill_val = 0 ) @@ -10247,7 +10447,8 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char /*========================================== * *------------------------------------------*/ -int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { +int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) +{ struct map_session_data* sd; struct status_change* sc; struct status_change_entry *sce; @@ -10267,7 +10468,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sc = status->get_sc(src); type = status->skill2sc(skill_id); - sce = (sc && type != -1)?sc->data[type]:NULL; + sce = (sc != NULL && type != SC_NONE) ? sc->data[type] : NULL; switch (skill_id) { //Skill effect. case WZ_METEOR: @@ -10276,6 +10477,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case HW_GANBANTEIN: case LG_EARTHDRIVE: case SC_ESCAPE: + case SU_CN_METEOR: break; //Effect is displayed on respective switch case. default: skill->castend_pos2_effect_unknown(src, &x, &y, &skill_id, &skill_lv, &tick, &flag); @@ -10340,10 +10542,11 @@ 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; } + FALLTHROUGH case MG_SAFETYWALL: { @@ -10353,6 +10556,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui return 0; // Don't consume gems if cast on LP } } + FALLTHROUGH case MG_FIREWALL: case MG_THUNDERSTORM: @@ -10462,7 +10666,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SO_ELEMENTAL_SHIELD: case RL_B_TRAP: case MH_XENO_SLASHER: - flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). + case SU_CN_POWDERING: + case SU_SV_ROOTTWIST: + flag |= 1; // Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). + FALLTHROUGH case GS_GROUNDDRIFT: //Ammo should be deleted right away. if ( skill_id == WM_SEVERE_RAINSTORM ) sc_start(src,src,SC_NO_SWITCH_EQUIP,100,0,skill->get_time(skill_id,skill_lv)); @@ -10482,7 +10689,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; @@ -10514,11 +10721,24 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui break; case WZ_METEOR: + case SU_CN_METEOR: { int area = skill->get_splash(skill_id, skill_lv); short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0; int i; +#if 0 + // The Meteor should inflict curse if Catnip fruit is consumed. + // Currently Catnip fruit is added as requirement. + if (sd && skill_id == SU_CN_METEOR) { + short item_idx = pc->search_inventory(sd, ITEMID_CATNIP_FRUIT); + if (item_idx >= 0) { + pc->delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_SKILL); + flag |= 1; + } + } +#endif + for( i = 0; i < 2 + (skill_lv>>1); i++ ) { // Creates a random Cell in the Splash Area tmpx = x - area + rnd()%(area * 2 + 1); @@ -10570,6 +10790,19 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } status_change_end(src, SC_HIDING, INVALID_TIMER); break; + case SU_LOPE: + { + if (map->list[src->m].flag.noteleport && !(map->list[src->m].flag.battleground || map_flag_gvg2(src->m))) { + x = src->x; + y = src->y; + } + clif->skill_nodamage(src, src, SU_LOPE, skill_lv, 1); + if(!map->count_oncell(src->m, x, y, BL_PC | BL_NPC | BL_MOB, 0) && map->getcell(src->m, src, x, y, CELL_CHKREACH)) { + clif->slide(src, x, y); + unit->movepos(src, x, y, 1, 0); + } + } + break; case AM_SPHEREMINE: case AM_CANNIBALIZE: { @@ -10589,7 +10822,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } // Correct info, don't change any of this! [Celest] - md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), class_, "", SZ_SMALL, AI_NONE); if (md) { md->master_id = src->id; md->special_state.ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA; @@ -10747,7 +10980,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: @@ -10769,7 +11002,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; /** @@ -10834,7 +11067,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NC_SILVERSNIPER: { - struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE); + struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE); if (md) { md->master_id = src->id; md->special_state.ai = AI_FLORA; @@ -10884,7 +11117,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); @@ -11039,7 +11272,8 @@ int skill_dance_overlap_sub(struct block_list *bl, va_list ap) //Does the song/dance overlapping -> dissonance check. [Skotlex] //When flag is 0, this unit is about to be removed, cancel the dissonance effect //When 1, this unit has been positioned, so start the cancel effect. -int skill_dance_overlap(struct skill_unit* su, int flag) { +int skill_dance_overlap(struct skill_unit* su, int flag) +{ if (!su || !su->group || !(su->group->state.song_dance&0x1)) return 0; @@ -11061,7 +11295,8 @@ int skill_dance_overlap(struct skill_unit* su, int flag) { * @param flag 1 Revert * @retval true success **/ -bool skill_dance_switch(struct skill_unit* su, int flag) { +bool skill_dance_switch(struct skill_unit* su, int flag) +{ static int prevflag = 1; // by default the backup is empty static struct skill_unit_group backup; struct skill_unit_group* group; @@ -11117,7 +11352,8 @@ bool skill_dance_switch(struct skill_unit* su, int flag) { * Initializes and sets a ground skill. * flag&1 is used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active) *------------------------------------------*/ -struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag) { +struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag) +{ struct skill_unit_group *group; int i,limit,val1=0,val2=0,val3=0; int target,interval,range,unit_flag,req_item=0; @@ -11147,9 +11383,10 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ sd = BL_CAST(BL_PC, src); st = status->get_status_data(src); + nullpo_retr(NULL, st); sc = status->get_sc(src); // for traps, firewall and fogwall - celest - switch( skill_id ) { + switch (skill_id) { case SO_ELEMENTAL_SHIELD: val2 = 300 * skill_lv + 65 * (st->int_ + status->get_lv(src)) + st->max_sp; break; @@ -11218,8 +11455,10 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ case HT_ANKLESNARE: if( flag&2 ) val3 = SC_ESCAPE; + FALLTHROUGH case HT_SHOCKWAVE: val1=skill_lv*15+10; + FALLTHROUGH case HT_SANDMAN: case MA_SANDMAN: case HT_CLAYMORETRAP: @@ -11244,7 +11483,7 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ case RA_ICEBOUNDTRAP: { struct skill_condition req = skill->get_requirement(sd,skill_id,skill_lv); - ARR_FIND(0, MAX_SKILL_ITEM_REQUIRE, i, req.itemid[i] && (req.itemid[i] == ITEMID_TRAP || req.itemid[i] == ITEMID_TRAP_ALLOY)); + ARR_FIND(0, MAX_SKILL_ITEM_REQUIRE, i, req.itemid[i] && (req.itemid[i] == ITEMID_BOOBY_TRAP || req.itemid[i] == ITEMID_SPECIAL_ALLOY_TRAP)); if( i != MAX_SKILL_ITEM_REQUIRE && req.itemid[i] ) req_item = req.itemid[i]; if( map_flag_gvg2(src->m) || map->list[src->m].flag.battleground ) @@ -11404,12 +11643,16 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ { case ELE_FIRE: subunt++; + FALLTHROUGH case ELE_WATER: subunt++; + FALLTHROUGH case ELE_POISON: subunt++; + FALLTHROUGH case ELE_DARK: subunt++; + FALLTHROUGH case ELE_WIND: break; default: @@ -11446,6 +11689,7 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ target = BCT_ALL; val1 = skill_lv + 1; val2 = 1; + FALLTHROUGH case WM_POEMOFNETHERWORLD: // Can't be placed on top of Land Protector. case SO_WATER_INSIGNIA: case SO_FIRE_INSIGNIA: @@ -11488,6 +11732,7 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ break; } + nullpo_retr(NULL, layout); nullpo_retr(NULL, group=skill->init_unitgroup(src,layout->count,skill_id,skill_lv,skill->get_unit_id(skill_id,flag&1)+subunt, limit, interval)); group->val1=val1; group->val2=val2; @@ -11628,10 +11873,15 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ return group; } -void skill_unitsetting1_unknown(struct block_list *src, uint16 *skill_id, uint16 *skill_lv, int16 *x, int16 *y, int *flag, int *val1, int *val2, int *val3) { +void skill_unitsetting1_unknown(struct block_list *src, uint16 *skill_id, uint16 *skill_lv, int16 *x, int16 *y, int *flag, int *val1, int *val2, int *val3) +{ } -void skill_unitsetting2_unknown(struct block_list *src, uint16 *skill_id, uint16 *skill_lv, int16 *x, int16 *y, int *flag, int *unit_flag, int *val1, int *val2, int *val3, struct skill_unit_group *group) { +void skill_unitsetting2_unknown(struct block_list *src, uint16 *skill_id, uint16 *skill_lv, int16 *x, int16 *y, int *flag, int *unit_flag, int *val1, int *val2, int *val3, struct skill_unit_group *group) +{ + nullpo_retv(group); + nullpo_retv(val2); + nullpo_retv(unit_flag); if (group->state.song_dance & 0x1) *val2 = *unit_flag & (UF_DANCE | UF_SONG); //Store whether this is a song/dance } @@ -11639,7 +11889,8 @@ void skill_unitsetting2_unknown(struct block_list *src, uint16 *skill_id, uint16 /*========================================== * *------------------------------------------*/ -int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick) { +int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick) +{ struct skill_unit_group *sg; struct block_list *ss; struct status_change *sc; @@ -11670,7 +11921,7 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick return 0; type = status->skill2sc(sg->skill_id); - sce = (sc && type != -1)?sc->data[type]:NULL; + sce = (sc != NULL && type != SC_NONE) ? sc->data[type] : NULL; skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still. switch (sg->unit_id) { case UNT_SPIDERWEB: @@ -11717,7 +11968,7 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick if (bl->type == BL_PC && !working) { struct map_session_data *sd = BL_UCAST(BL_PC, bl); - if ((!sd->chatID || battle_config.chat_warpportal) && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y) { + if ((sd->chat_id == 0 || battle_config.chat_warpportal) && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y) { int x = sg->val2>>16; int y = sg->val2&0xffff; int count = sg->val1>>16; @@ -11763,6 +12014,7 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick case UNT_HERMODE: if (sg->src_id!=bl->id && battle->check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0) status->change_clear_buffs(bl,1); //Should dispell only allies. + FALLTHROUGH case UNT_RICHMANKIM: case UNT_ETERNALCHAOS: case UNT_DRUMBATTLEFIELD: @@ -11777,6 +12029,11 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); break; case UNT_APPLEIDUN: + // If Aegis, apple of idun doesn't update its effect + if (!battle_config.song_timer_reset && sc && sce) + return 0; + // Let it fall through + FALLTHROUGH case UNT_WHISTLE: case UNT_ASSASSINCROSS: case UNT_POEMBRAGI: @@ -11784,19 +12041,34 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick case UNT_DONTFORGETME: case UNT_FORTUNEKISS: case UNT_SERVICEFORYOU: + // Don't buff themselves without link! if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) return 0; if (!sc) return 0; if (!sce) sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); + // From here songs are already active else if (battle_config.song_timer_reset && sce->val4 == 1) { - //Readjust timers since the effect will not last long. + // eA style: + // Readjust timers since the effect will not last long. sce->val4 = 0; timer->delete(sce->timer, status->change_timer); sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + } else if (!battle_config.song_timer_reset) { + // Aegis style: + // Songs won't renew unless finished + const struct TimerData *td = timer->get(sce->timer); + if (DIFF_TICK32(td->tick, timer->gettick()) < sg->interval) { + // Update with new values as the current one will vanish soon + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + sce->val1 = sg->skill_lv; // Why are we storing skill_lv as val1? + sce->val2 = sg->val1; + sce->val3 = sg->val2; + sce->val4 = 0; + } } - break; case UNT_FOGWALL: @@ -11851,6 +12123,13 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick sc_start(ss, bl, SC_VOLCANIC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); break; + case UNT_CATNIPPOWDER: + if (sg->src_id == bl->id || (status_get_mode(bl)&MD_BOSS)) + break; // Does not affect the caster or Boss. + if (sce == NULL && battle->check_target(&src->bl, bl, BCT_ENEMY) > 0) + sc_start(ss, bl, type, 100, sg->skill_lv, skill->get_time(sg->skill_id, sg->skill_lv)); + break; + case UNT_GD_LEADERSHIP: case UNT_GD_GLORYWOUNDS: case UNT_GD_SOULCOLD: @@ -11865,17 +12144,19 @@ 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) +{ } /*========================================== * *------------------------------------------*/ -int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int64 tick) { +int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int64 tick) +{ struct skill_unit_group *sg; struct block_list *ss; struct map_session_data *tsd; - struct status_data *tstatus, *bst; + struct status_data *tstatus; struct status_change *tsc, *ssc; struct skill_unit_group_tickset *ts; enum sc_type type; @@ -11899,7 +12180,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 return 0; tstatus = status->get_status_data(bl); - bst = status->get_base_status(bl); + nullpo_ret(tstatus); type = status->skill2sc(sg->skill_id); skill_id = sg->skill_id; @@ -11931,7 +12212,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_MANHOLE: return 0; default: - ShowError("skill_unit_onplace_timer: interval error (unit id %x)\n", sg->unit_id); + ShowError("skill_unit_onplace_timer: interval error (unit id %x)\n", (unsigned int)sg->unit_id); return 0; } } @@ -12056,12 +12337,12 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 tsc->sg_counter++; //SG hit counter. if (skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0) <= 0 && tsc) tsc->sg_counter=0; //Attack absorbed. - break; + break; #endif case GS_DESPERADO: if (rnd()%100 < src->val1) skill->attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); - break; + break; default: skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); } @@ -12142,11 +12423,13 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_VERDURETRAP: if( bl->type == BL_PC )// it won't work on players break; + FALLTHROUGH case UNT_FIRINGTRAP: case UNT_ICEBOUNDTRAP: case UNT_CLUSTERBOMB: if( bl->id == ss->id )// it won't trigger on caster break; + FALLTHROUGH case UNT_LANDMINE: case UNT_BLASTMINE: case UNT_SHOCKWAVE: @@ -12201,18 +12484,25 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 if (md && md->class_ == MOBID_EMPELIUM) break; #endif - if ((sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) - || (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1)) + // Don't buff themselves! + if ((sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER))) break; - heal = skill->calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true); - if( tsc && tsc->data[SC_AKAITSUKI] && heal ) - heal = ~heal + 1; - clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status->heal(bl, heal, 0, 0); - - if (!battle_config.song_timer_reset) + // Aegis style + // Check if the remaining time is enough to survive the next update + if (!battle_config.song_timer_reset + && !(tsc && tsc->data[type] && tsc->data[type]->val4 == 1)) { + // Apple of Idun is not active. Start it now sc_start4(ss, bl, type, 100, sg->skill_lv, sg->val1, sg->val2, 0, sg->limit); + } + + if (tstatus->hp < tstatus->max_hp) { + heal = skill->calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true); + if( tsc && tsc->data[SC_AKAITSUKI] && heal ) + heal = ~heal + 1; + clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); + status->heal(bl, heal, 0, 0); + } } break; case UNT_POEMBRAGI: @@ -12222,12 +12512,30 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_DONTFORGETME: case UNT_FORTUNEKISS: case UNT_SERVICEFORYOU: - if (battle_config.song_timer_reset - || (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1) - || (sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) - ) + // eA style: doesn't need this + if (battle_config.song_timer_reset) + break; + // Don't let buff themselves! + if (sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) break; + // Aegis style + // Check if song has enough time to survive the next check + if (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1) { + const struct TimerData *td = timer->get(tsc->data[type]->timer); + if (DIFF_TICK32(td->tick, timer->gettick()) < sg->interval) { + // Update with new values as the current one will vanish + timer->delete(tsc->data[type]->timer, status->change_timer); + tsc->data[type]->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + tsc->data[type]->val1 = sg->skill_lv; + tsc->data[type]->val2 = sg->val1; + tsc->data[type]->val3 = sg->val2; + tsc->data[type]->val4 = 0; + } + break; // Had enough time or not, it now has. Exit + } + + // Song was not active. Start it now sc_start4(ss, bl, type, 100, sg->skill_lv, sg->val1, sg->val2, 0, sg->limit); break; case UNT_TATAMIGAESHI: @@ -12413,6 +12721,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_STEALTHFIELD: if( bl->id == sg->src_id ) break; // Don't work on Self (video shows that) + FALLTHROUGH case UNT_NEUTRALBARRIER: sc_start(ss,bl,type,100,sg->skill_lv,sg->interval + 100); break; @@ -12547,6 +12856,8 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 if (tsc && (tsc->data[SC_HALLUCINATIONWALK] || tsc->data[SC_VACUUM_EXTREME])) { return 0; } else { + struct status_data *bst = status->get_base_status(bl); + nullpo_ret(bst); sg->limit -= 1000 * bst->str/20; sc_start(ss, bl, SC_VACUUM_EXTREME, 100, sg->skill_lv, sg->limit); @@ -12603,6 +12914,33 @@ 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; + case UNT_SV_ROOTTWIST: + if (status_get_mode(bl)&MD_BOSS) { + break; + } + if (tsc) { + if (!sg->val2) { + int sec = skill->get_time(sg->skill_id, sg->skill_lv); + + if (sc_start2(ss, bl, type, 100, sg->skill_lv, sg->group_id, sec)) { + const struct TimerData* td = ((tsc->data[type])? timer->get(tsc->data[type]->timer) : NULL); + + if (td != NULL) + sec = DIFF_TICK32(td->tick, tick); + clif->fixpos(bl); + sg->val2 = bl->id; + } else { // Couldn't trap it? + sec = 7000; + } + sg->limit = DIFF_TICK32(tick, sg->tick) + sec; + } else if (tsc->data[type] && bl->id == sg->val2) { + skill->attack(skill->get_type(SU_SV_ROOTTWIST_ATK), ss, &src->bl, bl, SU_SV_ROOTTWIST_ATK, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION); + } + } + break; + default: + skill->unit_onplace_timer_unknown(src, bl, &tick); + break; } if (bl->type == BL_MOB && ss != bl) @@ -12610,10 +12948,16 @@ 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 *------------------------------------------*/ -int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) { +int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) +{ struct skill_unit_group *sg; struct status_change *sc; struct status_change_entry *sce; @@ -12624,7 +12968,7 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) nullpo_ret(sg=src->group); sc = status->get_sc(bl); type = status->skill2sc(sg->skill_id); - sce = (sc && type != -1)?sc->data[type]:NULL; + sce = (sc != NULL && type != SC_NONE) ? sc->data[type] : NULL; if( bl->prev == NULL || (status->isdead(bl) && sg->unit_id != UNT_ANKLESNARE && sg->unit_id != UNT_SPIDERWEB && sg->unit_id != UNT_THORNS_TRAP) @@ -12678,7 +13022,8 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) /*========================================== * Triggered when a char steps out of a skill group (entirely) [Skotlex] *------------------------------------------*/ -int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { +int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) +{ struct status_change *sc; struct status_change_entry *sce; enum sc_type type; @@ -12688,7 +13033,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { sc = NULL; type = status->skill2sc(skill_id); - sce = (sc && type != -1)?sc->data[type]:NULL; + sce = (sc != NULL && type != SC_NONE) ? sc->data[type] : NULL; switch (skill_id) { case WZ_QUAGMIRE: @@ -12749,8 +13094,9 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { case DC_DONTFORGETME: case DC_FORTUNEKISS: case DC_SERVICEFORYOU: - if ((battle_config.song_timer_reset && sce) // athena style - || (!battle_config.song_timer_reset && sce && sce->val4 != 1) + + if ((battle_config.song_timer_reset && sce) // eAthena style: update everytime + || (!battle_config.song_timer_reset && sce && sce->val4 != 1) // Aegis style: update only when it was not a reduced effect ) { timer->delete(sce->timer, status->change_timer); //NOTE: It'd be nice if we could get the skill_lv for a more accurate extra time, but alas... @@ -12762,7 +13108,8 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { case PF_FOGWALL: if (sce) { status_change_end(bl, type, INVALID_TIMER); - if ((sce=sc->data[SC_BLIND])) { + nullpo_retb(sc); + if ((sce = sc->data[SC_BLIND])) { if (bl->type == BL_PC) //Players get blind ended immediately, others have it still for 30 secs. [Skotlex] status_change_end(bl, SC_BLIND, INVALID_TIMER); else { @@ -12790,14 +13137,19 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { * flag&1: Invoke onplace function (otherwise invoke onout) * flag&4: Invoke a onleft call (the unit might be scheduled for deletion) *------------------------------------------*/ -int skill_unit_effect(struct block_list* bl, va_list ap) { +int skill_unit_effect(struct block_list* bl, va_list ap) +{ struct skill_unit* su = va_arg(ap,struct skill_unit*); - struct skill_unit_group* group = su->group; + struct skill_unit_group* group; int64 tick = va_arg(ap,int64); unsigned int flag = va_arg(ap,unsigned int); uint16 skill_id; bool dissonance; + nullpo_ret(bl); + nullpo_ret(su); + group = su->group; + if( (!su->alive && !(flag&4)) || bl->prev == NULL ) return 0; @@ -12829,7 +13181,8 @@ int skill_unit_effect(struct block_list* bl, va_list ap) { /*========================================== * *------------------------------------------*/ -int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl, int64 damage, int64 tick) { +int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl, int64 damage, int64 tick) +{ struct skill_unit_group *sg; nullpo_ret(src); @@ -12892,7 +13245,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) return 0; if( skill->get_inf2(skill_id)&INF2_CHORUS_SKILL ) { - if( tsd->status.party_id == sd->status.party_id && (tsd->class_&MAPID_THIRDMASK) == MAPID_MINSTRELWANDERER ) + if (tsd->status.party_id == sd->status.party_id && (tsd->job & MAPID_THIRDMASK) == MAPID_MINSTRELWANDERER) p_sd[(*c)++] = tsd->bl.id; return 1; } else { @@ -12901,24 +13254,23 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) case PR_BENEDICTIO: { uint8 dir = map->calc_dir(&sd->bl,tsd->bl.x,tsd->bl.y); dir = (unit->getdir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing. - if ((tsd->class_&MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == 2 || dir == 6) //Must be standing to the left/right of Priest. + if ((tsd->job & MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == 2 || dir == 6) //Must be standing to the left/right of Priest. && sd->status.sp >= 10) p_sd[(*c)++]=tsd->bl.id; return 1; } case AB_ADORAMUS: // Adoramus does not consume Blue Gemstone when there is at least 1 Priest class next to the caster - if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST ) + if ((tsd->job & MAPID_UPPERMASK) == MAPID_PRIEST) p_sd[(*c)++] = tsd->bl.id; return 1; case WL_COMET: // Comet does not consume Red Gemstones when there is at least 1 Warlock class next to the caster - if( ( tsd->class_&MAPID_THIRDMASK ) == MAPID_WARLOCK ) + if ((tsd->job & MAPID_THIRDMASK) == MAPID_WARLOCK) p_sd[(*c)++] = tsd->bl.id; return 1; case LG_RAYOFGENESIS: - if( tsd->status.party_id == sd->status.party_id && (tsd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD && - tsd->sc.data[SC_BANDING] ) + if (tsd->status.party_id == sd->status.party_id && (tsd->job & MAPID_THIRDMASK) == MAPID_ROYAL_GUARD && tsd->sc.data[SC_BANDING]) p_sd[(*c)++] = tsd->bl.id; return 1; default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex] @@ -12927,7 +13279,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) if(pc_issit(tsd) || !unit->can_move(&tsd->bl)) return 0; if (sd->status.sex != tsd->status.sex && - (tsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && + (tsd->job & MAPID_UPPERMASK) == MAPID_BARDDANCER && (skill_lv = pc->checkskill(tsd, skill_id)) > 0 && (tsd->weapontype1==W_MUSICAL || tsd->weapontype1==W_WHIP) && sd->status.party_id && tsd->status.party_id && @@ -12950,12 +13302,16 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) /*========================================== * Checks and stores partners for ensemble skills [Skotlex] *------------------------------------------*/ -int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, uint16* skill_lv, int range, int cast_flag) { +int skill_check_pc_partner(struct map_session_data *sd, uint16 skill_id, uint16* skill_lv, int range, int cast_flag) +{ static int c=0; static int p_sd[2] = { 0, 0 }; int i; bool is_chorus = ( skill->get_inf2(skill_id)&INF2_CHORUS_SKILL ); + nullpo_ret(sd); + nullpo_ret(skill_lv); + if (!battle_config.player_skill_partner_check || pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) return is_chorus ? MAX_PARTY : 99; //As if there were infinite partners. @@ -13032,6 +13388,7 @@ int skill_check_condition_mob_master_sub (struct block_list *bl, va_list ap) *------------------------------------------*/ int skill_isammotype (struct map_session_data *sd, int skill_id) { + nullpo_ret(sd); return ( battle_config.arrow_decrement==2 && (sd->status.weapon == W_BOW || (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) && @@ -13071,14 +13428,16 @@ bool skill_is_combo( int skill_id ) return false; } -int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { +int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) +{ struct status_data *st; struct status_change *sc; struct skill_condition require; nullpo_ret(sd); - if (sd->chatID) return 0; + if (sd->chat_id != 0) + return 0; if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id) { //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] @@ -13167,8 +13526,10 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case SG_FUSION: case RA_WUGDASH: case KO_YAMIKUMO: - if( sc && sc->data[status->skill2sc(skill_id)] ) + case SU_HIDE: + if (sc && sc->data[status->skill2sc(skill_id)]) return 1; + FALLTHROUGH default: { int ret = skill->check_condition_castbegin_off_unknown(sc, &skill_id); @@ -13275,6 +13636,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case SA_CASTCANCEL: if(sd->ud.skilltimer == INVALID_TIMER) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -13367,7 +13729,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case TK_MISSION: - if( (sd->class_&MAPID_UPPERMASK) != MAPID_TAEKWON ) { + if ((sd->job & MAPID_UPPERMASK) != MAPID_TAEKWON) { // Cannot be used by Non-Taekwon classes clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -13379,7 +13741,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case TK_READYSTORM: case TK_READYTURN: case TK_JUMPKICK: - if( (sd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER ) { + if ((sd->job & MAPID_UPPERMASK) == MAPID_SOUL_LINKER) { // Soul Linkers cannot use this skill clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -13390,7 +13752,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case TK_STORMKICK: case TK_DOWNKICK: case TK_COUNTER: - if ((sd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) + if ((sd->job & MAPID_UPPERMASK) == MAPID_SOUL_LINKER) return 0; //Anti-Soul Linker check in case you job-changed with Stances active. if(!(sc && sc->data[SC_COMBOATTACK]) || sc->data[SC_COMBOATTACK]->val1 == TK_JUMPKICK) return 0; //Combo needs to be ready @@ -13402,7 +13764,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id status_change_end(&sd->bl, SC_COMBOATTACK, INVALID_TIMER); return 0; } - if(sc->data[SC_COMBOATTACK]->val1 != skill_id && !( sd && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )) { + if (sc->data[SC_COMBOATTACK]->val1 != skill_id + && !(sd != NULL && sd->status.base_level >= 90 && pc->fame_rank(sd->status.char_id, RANKTYPE_TAEKWON) > 0)) { //Cancel combo wait. unit->cancel_combo(&sd->bl); return 0; @@ -13524,6 +13887,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case GD_EMERGENCYCALL: // other checks were already done in skillnotok() if (!sd->status.guild_id || !sd->state.gmaster_flag) @@ -13546,6 +13910,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case NJ_BUNSINJYUTSU: if (!(sc && sc->data[SC_NJ_NEN])) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -13584,7 +13949,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id { int count = 0, i; for( i = 0; i < MAX_INVENTORY; i ++ ) - if( sd->status.inventory[i].nameid == ITEMID_ANCILLA ) + if (sd->status.inventory[i].nameid == ITEMID_ANSILA) count += sd->status.inventory[i].amount; if( count >= 3 ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_ANCILLA_NUMOVER, 0); @@ -13872,6 +14237,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case ST_CART: if(!pc_iscarton(sd)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_CART,0); @@ -13965,11 +14331,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case ST_MH_GRAPPLING: if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val2 == MH_MD_GRAPPLING)){ clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } + FALLTHROUGH case ST_PECO: if (!pc_isridingpeco(sd)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -14018,25 +14386,26 @@ 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) { +int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) +{ struct skill_condition require; struct status_data *st; int i; @@ -14044,7 +14413,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, nullpo_ret(sd); - if( sd->chatID ) + if (sd->chat_id != 0) return 0; if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { @@ -14213,7 +14582,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, cause = USESKILL_FAIL_BLUEJAMSTONE; break; case ITEMID_HOLY_WATER: cause = USESKILL_FAIL_HOLYWATER; break; - case ITEMID_ANCILLA: + case ITEMID_ANSILA: cause = USESKILL_FAIL_ANCILLA; break; case ITEMID_ACCELERATOR: case ITEMID_HOVERING_BOOSTER: @@ -14240,12 +14609,14 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, return 1; } -void skill_check_condition_castend_unknown(struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv) { +void skill_check_condition_castend_unknown(struct map_session_data* sd, uint16 *skill_id, uint16 *skill_lv) +{ } // type&2: consume items (after skill was used) // type&1: consume the others (before skill was used) -int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type) { +int skill_consume_requirement(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type) +{ struct skill_condition req; nullpo_ret(sd); @@ -14326,7 +14697,8 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin return 1; } -struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { +struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) +{ struct skill_condition req; struct status_data *st; struct status_change *sc; @@ -14368,7 +14740,8 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 case TK_READYTURN: case SG_FUSION: case KO_YAMIKUMO: - if( sc && sc->data[status->skill2sc(skill_id)] ) + case SU_HIDE: + if (sc && sc->data[status->skill2sc(skill_id)]) return req; /* Fall through */ default: @@ -14524,7 +14897,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if ((item_index = pc->search_inventory(sd, req.itemid[i])) == INDEX_NOT_FOUND || sd->status.inventory[item_index].amount < req.amount[i] ) { - req.itemid[i] = ITEMID_TRAP_ALLOY; + req.itemid[i] = ITEMID_SPECIAL_ALLOY_TRAP; req.amount[i] = 1; } break; @@ -14551,14 +14924,14 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 switch(skill_lv) { case 1: case 2: - req.itemid[1] = ITEMID_REPAIR_A; + req.itemid[1] = ITEMID_REPAIRA; break; case 3: case 4: - req.itemid[1] = ITEMID_REPAIR_B; + req.itemid[1] = ITEMID_REPAIRB; break; case 5: - req.itemid[1] = ITEMID_REPAIR_C; + req.itemid[1] = ITEMID_REPAIRC; break; } req.amount[1] = 1; @@ -14656,12 +15029,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) @@ -14671,7 +15044,8 @@ void skill_get_requirement_unknown(struct status_change *sc, struct map_session_ /*========================================== * Does cast-time reductions based on dex, item bonuses and config setting *------------------------------------------*/ -int skill_castfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { +int skill_castfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) +{ int time = skill->get_cast(skill_id, skill_lv); nullpo_ret(bl); @@ -14721,11 +15095,13 @@ int skill_castfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { /*========================================== * Does cast-time reductions based on sc data. *------------------------------------------*/ -int skill_castfix_sc (struct block_list *bl, int time) { +int skill_castfix_sc (struct block_list *bl, int time) +{ struct status_change *sc = status->get_sc(bl); if( time < 0 ) return 0; + nullpo_ret(bl); if( bl->type == BL_MOB ) // mobs casttime is fixed nothing to alter. return time; @@ -14754,7 +15130,9 @@ int skill_castfix_sc (struct block_list *bl, int time) { //ShowInfo("Castime castfix_sc = %d\n",time); return time; } -int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv) { + +int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv) +{ #ifdef RENEWAL_CAST struct status_change *sc = status->get_sc(bl); struct map_session_data *sd = BL_CAST(BL_PC,bl); @@ -14762,6 +15140,7 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 if( time < 0 ) return 0; + nullpo_ret(bl); if( bl->type == BL_MOB ) // mobs casttime is fixed nothing to alter. return (int)time; @@ -14833,6 +15212,7 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 case WZ_FIREPILLAR: if(skill_lv < 5) break; + FALLTHROUGH case HW_GRAVITATION: case MG_SAFETYWALL: case MG_STONECURSE: @@ -14894,7 +15274,8 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 /*========================================== * Does delay reductions based on dex/agi, sc data, item bonuses, ... *------------------------------------------*/ -int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { +int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) +{ int delaynodex = skill->get_delaynodex(skill_id, skill_lv); int time = skill->get_delay(skill_id, skill_lv); struct map_session_data *sd; @@ -14993,7 +15374,8 @@ struct square { int val2[5]; }; -void skill_brandishspear_first (struct square *tc, uint8 dir, int16 x, int16 y) { +void skill_brandishspear_first (struct square *tc, uint8 dir, int16 x, int16 y) +{ nullpo_retv(tc); if(dir == 0){ @@ -15088,7 +15470,8 @@ void skill_brandishspear_first (struct square *tc, uint8 dir, int16 x, int16 y) } -void skill_brandishspear_dir (struct square* tc, uint8 dir, int are) { +void skill_brandishspear_dir (struct square* tc, uint8 dir, int are) +{ int c; nullpo_retv(tc); @@ -15106,11 +15489,17 @@ void skill_brandishspear_dir (struct square* tc, uint8 dir, int are) { } } -void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { +void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) +{ int c,n=4; - uint8 dir = map->calc_dir(src,bl->x,bl->y); + uint8 dir; struct square tc; - int x=bl->x,y=bl->y; + int x, y; + + nullpo_retv(bl); + x = bl->x; + y = bl->y; + dir = map->calc_dir(src, x, y); skill->brandishspear_first(&tc,dir,x,y); skill->brandishspear_dir(&tc,dir,4); skill->area_temp[1] = bl->id; @@ -15155,7 +15544,8 @@ void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 s /*========================================== * Weapon Repair [Celest/DracoRPG] *------------------------------------------*/ -void skill_repairweapon (struct map_session_data *sd, int idx) { +void skill_repairweapon (struct map_session_data *sd, int idx) +{ int material; int materials[4] = { ITEMID_IRON_ORE, @@ -15177,7 +15567,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) ) ){ @@ -15196,7 +15586,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); @@ -15261,20 +15652,20 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) return; } - per = status->get_refine_chance(ditem->wlv, (int)item->refine) * 10; + per = status->get_refine_chance(ditem->wlv, (int)item->refine, REFINE_CHANCE_TYPE_NORMAL) * 10; // Aegis leaked formula. [malufett] - if( sd->status.class_ == JOB_MECHANIC_T ) + 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_OTHER); // FIXME: is this the correct reason flag? + pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE); // FIXME: is this the correct reason flag? if (per > rnd() % 1000) { int ep = 0; - logs->pick_pc(sd, LOG_TYPE_OTHER, -1, item, ditem); + logs->pick_pc(sd, LOG_TYPE_REFINE, -1, item, ditem); item->refine++; - logs->pick_pc(sd, LOG_TYPE_OTHER, 1, item, ditem); + logs->pick_pc(sd, LOG_TYPE_REFINE, 1, item, ditem); if(item->equip) { ep = item->equip; pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); @@ -15290,16 +15681,16 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) item->card[0] == CARD0_FORGE && (int)MakeDWord(item->card[2],item->card[3]) == sd->status.char_id) { // Fame point system [DracoRPG] - switch(ditem->wlv){ - case 1: - pc->addfame(sd,1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point - break; - case 2: - pc->addfame(sd,25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point - break; - case 3: - pc->addfame(sd,1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point - break; + switch (ditem->wlv) { + case 1: + pc->addfame(sd, RANKTYPE_BLACKSMITH, 1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point + break; + case 2: + pc->addfame(sd, RANKTYPE_BLACKSMITH, 25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point + break; + case 3: + pc->addfame(sd, RANKTYPE_BLACKSMITH, 1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point + break; } } } else { @@ -15307,7 +15698,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) if(item->equip) pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); clif->refine(sd->fd,1,idx,item->refine); - pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_OTHER); + pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE); clif->misceffect(&sd->bl,2); clif->emotion(&sd->bl, E_OMG); } @@ -15498,10 +15889,12 @@ int skill_frostjoke_scream(struct block_list *bl, va_list ap) /*========================================== * *------------------------------------------*/ -void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill_lv, cell_t cell, bool flag) { +void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill_lv, cell_t cell, bool flag) +{ int range = skill->get_unit_range(skill_id,skill_lv); int x,y; + nullpo_retv(src); for( y = src->bl.y - range; y <= src->bl.y + range; ++y ) for( x = src->bl.x - range; x <= src->bl.x + range; ++x ) map->list[src->bl.m].setcell(src->bl.m, x, y, cell, flag); @@ -15510,11 +15903,14 @@ void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill /*========================================== * *------------------------------------------*/ -int skill_attack_area(struct block_list *bl, va_list ap) { +int skill_attack_area(struct block_list *bl, va_list ap) +{ struct block_list *src,*dsrc; int atk_type,skill_id,skill_lv,flag,type; int64 tick; + nullpo_ret(bl); + if(status->isdead(bl)) return 0; @@ -15594,7 +15990,8 @@ int skill_clear_group (struct block_list *bl, int flag) /*========================================== * Returns the first element field found [Skotlex] *------------------------------------------*/ -struct skill_unit_group *skill_locate_element_field(struct block_list *bl) { +struct skill_unit_group *skill_locate_element_field(struct block_list *bl) +{ struct unit_data *ud = unit->bl2ud(bl); int i; nullpo_ret(bl); @@ -15932,7 +16329,8 @@ int skill_trap_splash(struct block_list *bl, va_list ap) /*========================================== * *------------------------------------------*/ -int skill_enchant_elemental_end (struct block_list *bl, int type) { +int skill_enchant_elemental_end(struct block_list *bl, int type) +{ struct status_change *sc; const enum sc_type scs[] = { SC_ENCHANTPOISON, SC_ASPERSIO, SC_PROPERTYFIRE, SC_PROPERTYWATER, SC_PROPERTYWIND, SC_PROPERTYGROUND, SC_PROPERTYDARK, SC_PROPERTYTELEKINESIS, SC_ENCHANTARMS }; int i; @@ -15950,14 +16348,15 @@ int skill_enchant_elemental_end (struct block_list *bl, int type) { bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce) { - static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; - static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; bool wall = true; + nullpo_retr(false, bl); if( (bl->type == BL_PC && battle_config.pc_cloak_check_type&1) || (bl->type != BL_PC && battle_config.monster_cloak_check_type&1) ) { //Check for walls. + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; int i; ARR_FIND( 0, 8, i, map->getcell(bl->m, bl, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) @@ -15986,7 +16385,8 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce /** * Verifies if an user can use SC_CLOAKING **/ -bool skill_can_cloak(struct map_session_data *sd) { +bool skill_can_cloak(struct map_session_data *sd) +{ nullpo_retr(false, sd); //Avoid cloaking with no wall and low skill level. [Skotlex] @@ -16015,11 +16415,12 @@ int skill_check_cloaking_end(struct block_list *bl, va_list ap) bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce) { - static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; - static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; bool wall = true; + nullpo_retr(false, bl); if( bl->type == BL_PC ) { //Check for walls. + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; int i; ARR_FIND( 0, 8, i, map->getcell(bl->m, bl, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) @@ -16079,7 +16480,8 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit) /*========================================== * *------------------------------------------*/ -struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2) { +struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2) +{ struct skill_unit *su; nullpo_retr(NULL, group); @@ -16131,7 +16533,8 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int /*========================================== * *------------------------------------------*/ -int skill_delunit (struct skill_unit* su) { +int skill_delunit (struct skill_unit* su) +{ struct skill_unit_group *group; nullpo_ret(su); @@ -16452,6 +16855,7 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list struct skill_unit_group_tickset *set; nullpo_ret(bl); + nullpo_ret(group); if (group->interval==-1) return NULL; @@ -16474,7 +16878,7 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list } if (j == -1) { - ShowWarning ("skill_unitgrouptickset_search: tickset is full. ( failed for skill '%s' on unit %d )\n",skill->get_name(group->skill_id),bl->type); + ShowWarning ("skill_unitgrouptickset_search: tickset is full. ( failed for skill '%s' on unit %u )\n", skill->get_name(group->skill_id), bl->type); j = id % MAX_SKILLUNITGROUPTICKSET; } @@ -16486,10 +16890,16 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list /*========================================== * *------------------------------------------*/ -int skill_unit_timer_sub_onplace(struct block_list* bl, va_list ap) { - struct skill_unit* su = va_arg(ap,struct skill_unit *); - struct skill_unit_group* group = su->group; - int64 tick = va_arg(ap,int64); +int skill_unit_timer_sub_onplace(struct block_list* bl, va_list ap) +{ + struct skill_unit* su; + struct skill_unit_group* group; + int64 tick; + + su = va_arg(ap,struct skill_unit *); + nullpo_ret(su); + group = su->group; + tick = va_arg(ap,int64); if( !su->alive || bl->prev == NULL ) return 0; @@ -16510,12 +16920,18 @@ int skill_unit_timer_sub_onplace(struct block_list* bl, va_list ap) { /** * @see DBApply */ -int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { - struct skill_unit* su = DB->data2ptr(data); - struct skill_unit_group* group = su->group; +int skill_unit_timer_sub(union DBKey key, struct DBData *data, va_list ap) +{ + struct skill_unit* su; + struct skill_unit_group* group; int64 tick = va_arg(ap,int64); bool dissonance; - struct block_list* bl = &su->bl; + struct block_list* bl; + + su = DB->data2ptr(data); + nullpo_ret(su); + group = su->group; + bl = &su->bl; if( !su->alive ) return 0; @@ -16548,6 +16964,7 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { skill->delunit(su); break; } + FALLTHROUGH case UNT_SKIDTRAP: case UNT_LANDMINE: case UNT_SHOCKWAVE: @@ -16572,7 +16989,7 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { // revert unit back into a trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = group->item_id?group->item_id:ITEMID_TRAP; + item_tmp.nameid = group->item_id ? group->item_id : ITEMID_BOOBY_TRAP; item_tmp.identify = 1; map->addflooritem(bl, &item_tmp, 1, bl->m, bl->x, bl->y, 0, 0, 0, 0); } @@ -16625,7 +17042,7 @@ int skill_unit_timer_sub(DBKey key, 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); @@ -16723,7 +17140,8 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { /*========================================== * Executes on all skill units every SKILLUNITTIMER_INTERVAL milliseconds. *------------------------------------------*/ -int skill_unit_timer(int tid, int64 tick, int id, intptr_t data) { +int skill_unit_timer(int tid, int64 tick, int id, intptr_t data) +{ map->freeblock_lock(); skill->unit_db->foreach(skill->unit_db, skill->unit_timer_sub, tick); @@ -16749,6 +17167,7 @@ int skill_unit_move_sub(struct block_list* bl, va_list ap) uint16 skill_id; int i; + nullpo_ret(target); nullpo_ret(bl); Assert_ret(bl->type == BL_SKILL); su = BL_UCAST(BL_SKILL, bl); @@ -16835,7 +17254,8 @@ int skill_unit_move_sub(struct block_list* bl, va_list ap) * units to figure out when they have left a group. * flag&4: Force a onleft event (triggered when the bl is killed, for example) *------------------------------------------*/ -int skill_unit_move(struct block_list *bl, int64 tick, int flag) { +int skill_unit_move(struct block_list *bl, int64 tick, int flag) +{ nullpo_ret(bl); if( bl->prev == NULL ) @@ -16860,7 +17280,8 @@ int skill_unit_move(struct block_list *bl, int64 tick, int flag) { /*========================================== * *------------------------------------------*/ -int skill_unit_move_unit_group(struct skill_unit_group *group, int16 m, int16 dx, int16 dy) { +int skill_unit_move_unit_group(struct skill_unit_group *group, int16 m, int16 dx, int16 dy) +{ int i,j; int64 tick = timer->gettick(); int *m_flag; @@ -17012,7 +17433,8 @@ int skill_can_produce_mix (struct map_session_data *sd, int nameid, int trigger, /*========================================== * *------------------------------------------*/ -int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty) { +int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty) +{ int slot[3]; int i,sc,ele,idx,equip,wlv,make_per = 0,flag = 0,skill_lv = 0; int num = -1; // exclude the recipe @@ -17207,12 +17629,15 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, case ITEMID_HAGALAZ: case ITEMID_OTHILA: D -= 500; //Rank C + FALLTHROUGH case ITEMID_ISA: case ITEMID_WYRD: D -= 500; //Rank B + FALLTHROUGH case ITEMID_NAUTHIZ: case ITEMID_URUZ: D -= 500; //Rank A + FALLTHROUGH case ITEMID_BERKANA: case ITEMID_LUX_ANIMA: D -= 500; //Rank S @@ -17373,7 +17798,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, make_per = make_per * battle_config.wp_rate / 100; } - if (sd->class_&JOBL_BABY) //if it's a Baby Class + if ((sd->job & JOBL_BABY) != 0) //if it's a Baby Class make_per = (make_per * 50) / 100; //Baby penalty is 50% (bugreport:4847) if(make_per < 1) make_per = 1; @@ -17437,8 +17862,8 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, if(equip){ clif->produce_effect(sd,0,nameid); clif->misceffect(&sd->bl,3); - if(itemdb_wlv(nameid) >= 3 && ((ele? 1 : 0) + sc) >= 3) // Fame point system [DracoRPG] - pc->addfame(sd,10); // Success to forge a lv3 weapon with 3 additional ingredients = +10 fame point + if (itemdb_wlv(nameid) >= 3 && ((ele? 1 : 0) + sc) >= 3) // Fame point system [DracoRPG] + pc->addfame(sd, RANKTYPE_BLACKSMITH, 10); // Success to forge a lv3 weapon with 3 additional ingredients = +10 fame point } else { int fame = 0; tmp_item.amount = 0; @@ -17478,8 +17903,9 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, sd->potion_success_counter = 0; } - if (fame) - pc->addfame(sd,fame); + if (fame != 0 && (skill_id == AM_PHARMACY || skill_id == AM_TWILIGHT1 || skill_id == AM_TWILIGHT2 || skill_id == AM_TWILIGHT3)) { + pc->addfame(sd, RANKTYPE_ALCHEMIST, fame); + } //Visual effects and the like. switch (skill_id) { case AM_PHARMACY: @@ -17657,7 +18083,9 @@ int skill_arrow_create (struct map_session_data *sd, int nameid) return 0; } -int skill_poisoningweapon( struct map_session_data *sd, int nameid) { + +int skill_poisoningweapon(struct map_session_data *sd, int nameid) +{ sc_type type; int chance, i; nullpo_ret(sd); @@ -17680,7 +18108,7 @@ int skill_poisoningweapon( struct map_session_data *sd, int nameid) { return 0; } - status_change_end(&sd->bl, SC_POISONINGWEAPON, -1);//Status must be forced to end so that a new poison will be applied if a player decides to change poisons. [Rytech] + status_change_end(&sd->bl, SC_POISONINGWEAPON, INVALID_TIMER); // Status must be forced to end so that a new poison will be applied if a player decides to change poisons. [Rytech] chance = 2 + 2 * sd->menuskill_val; // 2 + 2 * skill_lv sc_start4(&sd->bl, &sd->bl, SC_POISONINGWEAPON, 100, pc->checkskill(sd, GC_RESEARCHNEWPOISON), //in Aegis it store the level of GC_RESEARCHNEWPOISON in val1 type, chance, 0, skill->get_time(GC_POISONINGWEAPON, sd->menuskill_val)); @@ -17688,7 +18116,8 @@ int skill_poisoningweapon( struct map_session_data *sd, int nameid) { return 0; } -void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id) { +void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id) +{ struct status_change *sc = status->get_sc(bl); // non-offensive and non-magic skills do not affect the status @@ -17712,7 +18141,8 @@ void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id) { } } -int skill_magicdecoy(struct map_session_data *sd, int nameid) { +int skill_magicdecoy(struct map_session_data *sd, int nameid) +{ int x, y, i, class_ = 0, skill_id; struct mob_data *md; nullpo_ret(sd); @@ -17734,16 +18164,16 @@ int skill_magicdecoy(struct map_session_data *sd, int nameid) { sd->menuskill_val = 0; switch (nameid) { - case ITEMID_SCARLET_POINT: + case ITEMID_SCARLET_PTS: class_ = MOBID_MAGICDECOY_FIRE; break; - case ITEMID_INDIGO_POINT: + case ITEMID_INDIGO_PTS: class_ = MOBID_MAGICDECOY_WATER; break; - case ITEMID_LIME_GREEN_POINT: + case ITEMID_LIME_GREEN_PTS: class_ = MOBID_MAGICDECOY_WIND; break; - case ITEMID_YELLOW_WISH_POINT: + case ITEMID_YELLOW_WISH_PTS: class_ = MOBID_MAGICDECOY_EARTH; break; } @@ -17763,7 +18193,8 @@ int skill_magicdecoy(struct map_session_data *sd, int nameid) { } // Warlock Spellbooks. [LimitLine/3CeAM] -int skill_spellbook (struct map_session_data *sd, int nameid) { +int skill_spellbook(struct map_session_data *sd, int nameid) +{ int i, max_preserve, skill_id, point; struct status_change *sc; @@ -17800,18 +18231,20 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { for(i = SC_SPELLBOOK7; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett] if( !sc->data[i] ){ sc->data[SC_READING_SB]->val2 += point; // increase points - sc_start4(&sd->bl,&sd->bl, (sc_type)i, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); + sc_start4(&sd->bl, &sd->bl, (sc_type)i, 100, skill_id, pc->checkskill(sd, skill_id), point, 0, INFINITE_DURATION); break; } } - }else{ - sc_start2(&sd->bl,&sd->bl, SC_READING_SB, 100, 0, point, INVALID_TIMER); - sc_start4(&sd->bl,&sd->bl, SC_SPELLBOOK7, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); + } else { + sc_start2(&sd->bl, &sd->bl, SC_READING_SB, 100, 0, point, INFINITE_DURATION); + sc_start4(&sd->bl, &sd->bl, SC_SPELLBOOK7, 100, skill_id, pc->checkskill(sd, skill_id), point, 0, INFINITE_DURATION); } return 1; } -int skill_select_menu(struct map_session_data *sd,uint16 skill_id) { + +int skill_select_menu(struct map_session_data *sd,uint16 skill_id) +{ int id, lv, prob, aslvl = 0, idx = 0; nullpo_ret(sd); @@ -17834,27 +18267,31 @@ int skill_select_menu(struct map_session_data *sd,uint16 skill_id) { sc_start4(&sd->bl,&sd->bl,SC__AUTOSHADOWSPELL,100,id,lv,prob,0,skill->get_time(SC_AUTOSHADOWSPELL,aslvl)); return 0; } -int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, unsigned short* item_list) { + +int skill_elementalanalysis(struct map_session_data *sd, uint16 skill_lv, const struct itemlist *item_list) +{ int i; nullpo_ret(sd); nullpo_ret(item_list); - if( n <= 0 ) + if (VECTOR_LENGTH(*item_list) <= 0) return 1; - for (i = 0; i < n; i++) { - int nameid, add_amount, del_amount, idx, product; + for (i = 0; i < VECTOR_LENGTH(*item_list); i++) { struct item tmp_item; - - idx = item_list[i*2+0]-2; - del_amount = item_list[i*2+1]; + const struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i); + int nameid, add_amount, product; + int del_amount = entry->amount; + int idx = entry->id; if( skill_lv == 2 ) del_amount -= (del_amount % 10); add_amount = (skill_lv == 1) ? del_amount * (5 + rnd()%5) : del_amount / 10 ; - if( (nameid = sd->status.inventory[idx].nameid) <= 0 || del_amount > sd->status.inventory[idx].amount ) { + if (idx < 0 || idx >= MAX_INVENTORY + || (nameid = sd->status.inventory[idx].nameid) <= 0 + || del_amount < 0 || del_amount > sd->status.inventory[idx].amount) { clif->skill_fail(sd,SO_EL_ANALYSIS,USESKILL_FAIL_LEVEL,0); return 1; } @@ -17904,7 +18341,8 @@ int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, return 0; } -int skill_changematerial(struct map_session_data *sd, int n, unsigned short *item_list) { +int skill_changematerial(struct map_session_data *sd, const struct itemlist *item_list) +{ int i, j, k, c, p = 0, nameid, amount; nullpo_ret(sd); @@ -17919,11 +18357,13 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite // Verification of overlap between the objects required and the list submitted. for( j = 0; j < MAX_PRODUCE_RESOURCE; j++ ) { if( skill->dbs->produce_db[i].mat_id[j] > 0 ) { - for( k = 0; k < n; k++ ) { - int idx = item_list[k*2+0]-2; + for (k = 0; k < VECTOR_LENGTH(*item_list); k++) { + const struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, k); + int idx = entry->id; + Assert_ret(idx >= 0 && idx < MAX_INVENTORY); + amount = entry->amount; nameid = sd->status.inventory[idx].nameid; - amount = item_list[k*2+1]; - if( nameid > 0 && sd->status.inventory[idx].identify == 0 ){ + if (nameid > 0 && sd->status.inventory[idx].identify == 0) { clif->msgtable_skill(sd, GN_CHANGEMATERIAL, MSG_SKILL_ITEM_NEED_IDENTIFY); return 0; } @@ -17936,7 +18376,7 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite break; // No more items required } p++; - } while(n == j && c == n); + } while (c == j && VECTOR_LENGTH(*item_list) == c); p--; if ( p > 0 ) { skill->produce_mix(sd,GN_CHANGEMATERIAL,skill->dbs->produce_db[i].nameid,0,0,0,p); @@ -17950,6 +18390,7 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite return 0; } + /** * for Royal Guard's LG_TRAMPLE **/ @@ -17985,10 +18426,12 @@ int skill_destroy_trap(struct block_list *bl, va_list ap) } return 0; } + /*========================================== * *------------------------------------------*/ -int skill_blockpc_end(int tid, int64 tick, int id, intptr_t data) { +int skill_blockpc_end(int tid, int64 tick, int id, intptr_t data) +{ struct map_session_data *sd = map->id2sd(id); struct skill_cd * cd = NULL; @@ -18040,7 +18483,8 @@ int skill_blockpc_end(int tid, int64 tick, int id, intptr_t data) { * @param tick the length of time the delay should last * @return 0 if successful, -1 otherwise */ -int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick) { +int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick) +{ struct skill_cd* cd = NULL; uint16 idx = skill->get_index(skill_id); int64 now = timer->gettick(); @@ -18135,7 +18579,9 @@ int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) return 1; } -int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { // [orn] +// [orn] +int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) +{ uint16 idx = skill->get_index(skill_id); nullpo_retr (-1, hd); @@ -18177,12 +18623,15 @@ int skill_blockmerc_start(struct mercenary_data *md, uint16 skill_id, int tick) md->blockskill[idx] = 1; return timer->add(timer->gettick() + tick, skill->blockmerc_end, md->bl.id, idx); } + /** * Adds a new skill unit entry for this player to recast after map load **/ -void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill_lv) { +void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill_lv) +{ struct skill_unit_save * sus = NULL; + nullpo_retv(sd); if( idb_exists(skill->usave_db,sd->status.char_id) ) { idb_remove(skill->usave_db,sd->status.char_id); } @@ -18195,9 +18644,12 @@ void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill return; } -void skill_usave_trigger(struct map_session_data *sd) { + +void skill_usave_trigger(struct map_session_data *sd) +{ struct skill_unit_save * sus = NULL; + nullpo_retv(sd); if( ! (sus = idb_get(skill->usave_db,sd->status.char_id)) ) { return; } @@ -18215,6 +18667,8 @@ int skill_split_atoi(char *str, int *val) { int i, j, step = 1; + nullpo_ret(val); + for (i=0; i<MAX_SKILL_LEVEL; i++) { if (!str) break; val[i] = atoi(str); @@ -18427,7 +18881,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) @@ -18528,7 +18982,13 @@ void skill_init_unit_layout (void) } -int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) { +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); @@ -18675,7 +19135,8 @@ int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) { return 0; } -int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) { +int skill_get_elemental_type(uint16 skill_id , uint16 skill_lv) +{ int type = 0; switch (skill_id) { @@ -18694,7 +19155,8 @@ int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) { * update stored skill cooldowns for player logout * @param sd the affected player structure */ -void skill_cooldown_save(struct map_session_data * sd) { +void skill_cooldown_save(struct map_session_data * sd) +{ int i; struct skill_cd* cd = NULL; int64 now = 0; @@ -18722,7 +19184,8 @@ void skill_cooldown_save(struct map_session_data * sd) { * reload stored skill cooldowns when a player logs in. * @param sd the affected player structure */ -void skill_cooldown_load(struct map_session_data * sd) { +void skill_cooldown_load(struct map_session_data * sd) +{ int i; struct skill_cd* cd = NULL; int64 now = 0; @@ -18746,225 +19209,14 @@ 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) { +bool skill_parse_row_producedb(char* split[], int columns, int current) +{ // ProduceItemID,ItemLV,RequireSkill,Requireskill_lv,MaterialID1,MaterialAmount1,...... int x,y; + int i; - int i = atoi(split[0]); + nullpo_retr(false, split); + i = atoi(split[0]); if( !i ) return false; @@ -18981,11 +19233,14 @@ bool skill_parse_row_producedb(char* split[], int columns, int current) { return true; } -bool skill_parse_row_createarrowdb(char* split[], int columns, int current) { +bool skill_parse_row_createarrowdb(char* split[], int columns, int current) +{ // SourceID,MakeID1,MakeAmount1,...,MakeID5,MakeAmount5 int x,y; - int i = atoi(split[0]); + int i; + nullpo_retr(false, split); + i = atoi(split[0]); if( !i ) return false; @@ -18998,12 +19253,19 @@ bool skill_parse_row_createarrowdb(char* split[], int columns, int current) { return true; } -bool skill_parse_row_spellbookdb(char* split[], int columns, int current) { + +bool skill_parse_row_spellbookdb(char* split[], int columns, int current) +{ // skill_id,PreservePoints - uint16 skill_id = atoi(split[0]); - int points = atoi(split[1]); - int nameid = atoi(split[2]); + uint16 skill_id; + int points; + int nameid; + + nullpo_retr(false, split); + skill_id = atoi(split[0]); + points = atoi(split[1]); + nameid = atoi(split[2]); if( !skill->get_index(skill_id) || !skill->get_max(skill_id) ) ShowError("spellbook_db: Invalid skill ID %d\n", skill_id); @@ -19021,10 +19283,16 @@ bool skill_parse_row_spellbookdb(char* split[], int columns, int current) { return false; } -bool skill_parse_row_improvisedb(char* split[], int columns, int current) { + +bool skill_parse_row_improvisedb(char* split[], int columns, int current) +{ // SkillID,Rate - uint16 skill_id = atoi(split[0]); - short j = atoi(split[1]); + uint16 skill_id; + short j; + + nullpo_retr(false, split); + skill_id = atoi(split[0]); + j = atoi(split[1]); if( !skill->get_index(skill_id) || !skill->get_max(skill_id) ) { ShowError("skill_improvise_db: Invalid skill ID %d\n", skill_id); @@ -19047,10 +19315,14 @@ bool skill_parse_row_improvisedb(char* split[], int columns, int current) { return true; } -bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) { + +bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) +{ // SkillID - uint16 skill_id = atoi(split[0]); + uint16 skill_id; + nullpo_retr(false, split); + skill_id = atoi(split[0]); if( !skill->get_index(skill_id) || !skill->get_max(skill_id) ) { ShowError("magicmushroom_db: Invalid skill ID %d\n", skill_id); return false; @@ -19065,9 +19337,13 @@ bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) { return true; } -bool skill_parse_row_reproducedb(char* split[], int column, int current) { - uint16 skill_id = atoi(split[0]); - uint16 idx = skill->get_index(skill_id); +bool skill_parse_row_reproducedb(char* split[], int column, int current) +{ + uint16 skill_id; + uint16 idx; + nullpo_retr(false, split); + skill_id = atoi(split[0]); + idx = skill->get_index(skill_id); if( !idx ) return false; @@ -19076,9 +19352,12 @@ bool skill_parse_row_reproducedb(char* split[], int column, int current) { return true; } -bool skill_parse_row_abradb(char* split[], int columns, int current) { +bool skill_parse_row_abradb(char* split[], int columns, int current) +{ // skill_id,DummyName,RequiredHocusPocusLevel,Rate - uint16 skill_id = atoi(split[0]); + uint16 skill_id; + nullpo_retr(false, split); + skill_id = atoi(split[0]); if( !skill->get_index(skill_id) || !skill->get_max(skill_id) ) { ShowError("abra_db: Invalid skill ID %d\n", skill_id); return false; @@ -19095,12 +19374,16 @@ bool skill_parse_row_abradb(char* split[], int columns, int current) { return true; } -bool skill_parse_row_changematerialdb(char* split[], int columns, int current) { +bool skill_parse_row_changematerialdb(char* split[], int columns, int current) +{ // ProductID,BaseRate,MakeAmount1,MakeAmountRate1...,MakeAmount5,MakeAmountRate5 - uint16 skill_id = atoi(split[0]); - short j = atoi(split[1]); + uint16 skill_id; + short j; int x,y; + nullpo_retr(false, split); + skill_id = atoi(split[0]); + j = atoi(split[1]); for(x=0; x<MAX_SKILL_PRODUCE_DB; x++){ if( skill->dbs->produce_db[x].nameid == skill_id ) if( skill->dbs->produce_db[x].req_skill == GN_CHANGEMATERIAL ) @@ -19128,19 +19411,1324 @@ 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; + + nullpo_retv(arr); + if (config_setting_is_group(conf)) { + for (i=0; i<MAX_SKILL_LEVEL; i++) { + char level[6]; // enough to contain "Lv100" in case of custom MAX_SKILL_LEVEL + 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; + + nullpo_retv(arr); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + if ((t=libconfig->setting_get_member(conf, "Element")) && config_setting_is_group(t)) { + int j = 0; + char lv[6]; // enough to contain "Lv100" in case of custom MAX_SKILL_LEVEL + + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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) +{ + nullpo_ret(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; + + nullpo_retv(sk); + 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) +{ + nullpo_ret(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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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; + + nullpo_retv(sk); + 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) +{ + nullpo_ret(type); + nullpo_ret(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; + + nullpo_retv(sk); + 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; + + nullpo_retr(false, sk); + 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 *------------------------------*/ -void skill_readdb(bool minimal) { +void skill_readdb(bool minimal) +{ // init skill db structures db_clear(skill->name2id_db); @@ -19153,26 +20741,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); @@ -19219,7 +20800,8 @@ void skill_reload(void) /*========================================== * *------------------------------------------*/ -int do_init_skill(bool minimal) { +int do_init_skill(bool minimal) +{ skill->name2id_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, MAX_SKILL_NAME_LENGTH); skill->read_db(minimal); @@ -19252,7 +20834,8 @@ int do_init_skill(bool minimal) { return 0; } -int do_final_skill(void) { +int do_final_skill(void) +{ db_destroy(skill->name2id_db); db_destroy(skill->group_db); db_destroy(skill->unit_db); @@ -19265,8 +20848,10 @@ int do_final_skill(void) { ers_destroy(skill->cd_entry_ers); return 0; } + /* initialize the interface */ -void skill_defaults(void) { +void skill_defaults(void) +{ const int skill_enchant_eff[5] = { 10, 14, 17, 19, 20 }; const int skill_deluge_eff[5] = { 5, 9, 12, 14, 15 }; @@ -19352,6 +20937,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; @@ -19397,7 +20983,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; @@ -19445,6 +21033,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; @@ -19455,11 +21044,30 @@ 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->validate_weapontype_sub = skill_validate_weapontype_sub; + skill->validate_ammotype_sub = skill_validate_ammotype_sub; + skill->validate_unit_flag_sub = skill_validate_unit_flag_sub; + 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; @@ -19516,4 +21124,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; } |