summaryrefslogtreecommitdiff
path: root/src/map/skill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/skill.c')
-rw-r--r--src/map/skill.c2879
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;
}