From c67c2b7435a13d7ce17b2075e22dc5c6036f702a Mon Sep 17 00:00:00 2001
From: Ben Longbons <b.r.longbons@gmail.com>
Date: Mon, 4 Feb 2013 00:49:50 -0800
Subject: Remove some more Skill-related stuff

---
 src/common/extract.hpp          |    2 +-
 src/common/nullpo.cpp           |    1 +
 src/common/nullpo.hpp           |   19 +-
 src/common/timer.cpp            |    2 +
 src/common/timer.hpp            |    1 +
 src/map/atcommand.cpp           |   43 +-
 src/map/battle.cpp              |  535 +----
 src/map/battle.hpp              |   19 +-
 src/map/battle.t.hpp            |  137 ++
 src/map/chat.cpp                |    3 +-
 src/map/chrif.cpp               |    3 +-
 src/map/clif.cpp                |  202 +-
 src/map/clif.hpp                |    5 +-
 src/map/itemdb.cpp              |    3 +-
 src/map/magic-expr-eval.hpp     |    7 -
 src/map/magic-expr.cpp          |   21 +-
 src/map/magic-interpreter.t.hpp |   15 +
 src/map/magic-stmt.cpp          |    6 +-
 src/map/map.cpp                 |  104 +-
 src/map/map.hpp                 |  162 +-
 src/map/map.t.hpp               |  183 +-
 src/map/mob.cpp                 |  501 +---
 src/map/mob.hpp                 |   14 +-
 src/map/mob.t.hpp               |   79 +-
 src/map/npc.cpp                 |   48 +-
 src/map/npc.hpp                 |    2 +-
 src/map/path.cpp                |   46 +-
 src/map/pc.cpp                  |  449 +---
 src/map/pc.hpp                  |    8 +-
 src/map/script.cpp              |    9 -
 src/map/skill.cpp               | 4882 +++++++--------------------------------
 src/map/skill.hpp               |   39 -
 src/map/skill.t.hpp             |    7 +-
 src/map/storage.cpp             |    9 +-
 34 files changed, 1558 insertions(+), 6008 deletions(-)

(limited to 'src')

diff --git a/src/common/extract.hpp b/src/common/extract.hpp
index c60ce2a..3198d5d 100644
--- a/src/common/extract.hpp
+++ b/src/common/extract.hpp
@@ -67,7 +67,7 @@ bool extract(const_string str, T *iv)
     // defer to integer version
     if (!extract(str, &v))
         return false;
-    // TODO check bounds ...
+    // TODO check bounds using enum min/max as in SSCANF
     *iv = static_cast<T>(v);
     return true;
 }
diff --git a/src/common/nullpo.cpp b/src/common/nullpo.cpp
index d7d489c..423ed8c 100644
--- a/src/common/nullpo.cpp
+++ b/src/common/nullpo.cpp
@@ -5,6 +5,7 @@
 #include "../poison.hpp"
 
 /// Actual output function
+static
 void nullpo_info(const char *file, int line, const char *func)
 {
     if (!file)
diff --git a/src/common/nullpo.hpp b/src/common/nullpo.hpp
index ad1084a..2d8644f 100644
--- a/src/common/nullpo.hpp
+++ b/src/common/nullpo.hpp
@@ -1,22 +1,22 @@
 /// return wrappers for unexpected NULL pointers
 #ifndef NULLPO_HPP
 #define NULLPO_HPP
-/// Comment this out to live dangerously
-# define NULLPO_CHECK
+/// Uncomment this to live dangerously
+/// (really exist to detect mostly-unused variables)
+//# define BUG_FREE
 
 /// All functions print to standard error (was: standard output)
 /// nullpo_ret(cond) - return 0 if given pointer is NULL
 /// nullpo_retv(cond) - just return (function returns void)
 /// nullpo_retr(rv, cond) - return given value instead
 
-# ifdef NULLPO_CHECK
-# define NLP_MARK __FILE__, __LINE__, __func__
+# ifndef BUG_FREE
 #  define nullpo_retr(ret, t) \
-    if (nullpo_chk(NLP_MARK, t)) \
+    if (nullpo_chk(__FILE__, __LINE__, __func__, t)) \
         return ret;
-# else // NULLPO_CHECK
-#  define nullpo_retr(ret, t) t;
-# endif // NULLPO_CHECK
+# else // BUG_FREE
+#  define nullpo_retr(ret, t) /*t*/
+# endif // BUG_FREE
 
 # define nullpo_ret(t) nullpo_retr(0, t)
 # define nullpo_retv(t) nullpo_retr(, t)
@@ -27,7 +27,4 @@
 bool nullpo_chk(const char *file, int line, const char *func,
         const void *target);
 
-/// Used only by map/battle.c
-void nullpo_info(const char *file, int line, const char *func);
-
 #endif // NULLPO_HPP
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index 65f04e0..92d284c 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -185,11 +185,13 @@ void delete_timer(timer_id id, timer_func func)
         FPRINTF(stderr, "delete_timer error : no such timer %d\n", id);
         abort();
     }
+#ifndef delete_timer
     if (timer_data[id].func != func)
     {
         FPRINTF(stderr, "Timer mismatch\n");
         abort();
     }
+#endif
     // "to let them disappear" - is this just in case?
     timer_data[id].func = NULL;
     timer_data[id].type = TIMER_ONCE_AUTODEL;
diff --git a/src/common/timer.hpp b/src/common/timer.hpp
index db4dedd..b00d48d 100644
--- a/src/common/timer.hpp
+++ b/src/common/timer.hpp
@@ -52,6 +52,7 @@ tick_t gettick(void);
 
 timer_id add_timer(tick_t, timer_func, custom_id_t, custom_data_t);
 timer_id add_timer_interval(tick_t, timer_func, custom_id_t, custom_data_t, interval_t);
+//#define delete_timer(tid, func) delete_timer(tid)
 void delete_timer(timer_id, timer_func);
 
 tick_t addtick_timer(timer_id, interval_t);
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index 211baac..a6994d5 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -1594,7 +1594,7 @@ int atcommand_heal(const int fd, struct map_session_data *sd,
     }
 
     if (hp < 0)            // display like damage
-        clif_damage(&sd->bl, &sd->bl, gettick(), 0, 0, -hp, 0, 4, 0);
+        clif_damage(&sd->bl, &sd->bl, gettick(), 0, 0, -hp, 0, DamageType::RETURNED, 0);
 
     if (hp != 0 || sp != 0)
     {
@@ -4614,11 +4614,10 @@ int atcommand_mapinfo(const int fd, struct map_session_data *sd,
     struct npc_data *nd = NULL;
     struct chat_data *cd = NULL;
     char map_name[100];
-    char direction[12];
+    const char *direction = NULL;
     int m_id, i, chat_num, list = 0;
 
     memset(map_name, '\0', sizeof(map_name));
-    memset(direction, '\0', sizeof(direction));
 
     sscanf(message, "%d %99[^\n]", &list, map_name);
 
@@ -4716,35 +4715,37 @@ int atcommand_mapinfo(const int fd, struct map_session_data *sd,
                 nd = map[m_id].npc[i];
                 switch (nd->dir)
                 {
-                    case 0:
-                        strcpy(direction, "North");
+                    case DIR_S:
+                        direction = "North";
                         break;
-                    case 1:
-                        strcpy(direction, "North West");
+                    case DIR_SW:
+                        direction = "North West";
                         break;
-                    case 2:
-                        strcpy(direction, "West");
+                    case DIR_W:
+                        direction = "West";
                         break;
-                    case 3:
-                        strcpy(direction, "South West");
+                    case DIR_NW:
+                        direction = "South West";
                         break;
-                    case 4:
-                        strcpy(direction, "South");
+                    case DIR_N:
+                        direction = "South";
                         break;
-                    case 5:
-                        strcpy(direction, "South East");
+                    case DIR_NE:
+                        direction = "South East";
                         break;
-                    case 6:
-                        strcpy(direction, "East");
+                    case DIR_E:
+                        direction = "East";
                         break;
-                    case 7:
-                        strcpy(direction, "North East");
+                    case DIR_SE:
+                        direction = "North East";
                         break;
+#if 0
                     case 9:
-                        strcpy(direction, "North");
+                        direction = "North";
                         break;
+#endif
                     default:
-                        strcpy(direction, "Unknown");
+                        direction = "Unknown";
                         break;
                 }
                 output = STRPRINTF(
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index 4d98b45..b431662 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -58,15 +58,15 @@ int battle_get_class(struct block_list *bl)
  * 戻りは整数で0以上
  *------------------------------------------
  */
-int battle_get_dir(struct block_list *bl)
+DIR battle_get_dir(struct block_list *bl)
 {
-    nullpo_ret(bl);
+    nullpo_retr(DIR_S, bl);
     if (bl->type == BL_MOB && (struct mob_data *) bl)
         return ((struct mob_data *) bl)->dir;
     else if (bl->type == BL_PC && (struct map_session_data *) bl)
         return ((struct map_session_data *) bl)->dir;
     else
-        return 0;
+        return DIR_S;
 }
 
 /*==========================================
@@ -591,22 +591,17 @@ int battle_get_matk2(struct block_list *bl)
 int battle_get_def(struct block_list *bl)
 {
     eptr<struct status_change, StatusChange> sc_data;
-    int def = 0, skilltimer = -1;
-    SkillID skillid = SkillID::ZERO;
+    int def = 0;
 
     nullpo_ret(bl);
     sc_data = battle_get_sc_data(bl);
     if (bl->type == BL_PC && (struct map_session_data *) bl)
     {
         def = ((struct map_session_data *) bl)->def;
-        skilltimer = ((struct map_session_data *) bl)->skilltimer;
-        skillid = ((struct map_session_data *) bl)->skillid;
     }
     else if (bl->type == BL_MOB && (struct mob_data *) bl)
     {
         def = ((struct mob_data *) bl)->stats[MOB_DEF];
-        skilltimer = ((struct mob_data *) bl)->skilltimer;
-        skillid = ((struct mob_data *) bl)->skillid;
     }
 
     if (def < 1000000)
@@ -622,13 +617,6 @@ int battle_get_def(struct block_list *bl)
                     && sc_data[SC_STONE].val2 == 0))
                 def >>= 1;
         }
-        //詠唱中は詠唱時減算率に基づいて減算
-        if (skilltimer != -1)
-        {
-            int def_rate = skill_get_castdef(skillid);
-            if (def_rate != 0)
-                def = (def * (100 - def_rate)) / 100;
-        }
     }
     if (def < 0)
         def = 0;
@@ -842,24 +830,22 @@ int battle_get_dmotion(struct block_list *bl)
     return ret;
 }
 
-int battle_get_element(struct block_list *bl)
+LevelElement battle_get_element(struct block_list *bl)
 {
-    int ret = 20;
+    LevelElement ret = {2, Element::neutral};
     eptr<struct status_change, StatusChange> sc_data;
 
     nullpo_retr(ret, bl);
     sc_data = battle_get_sc_data(bl);
     if (bl->type == BL_MOB && (struct mob_data *) bl)   // 10の位=Lv*2、1の位=属性
         ret = ((struct mob_data *) bl)->def_ele;
-    else if (bl->type == BL_PC && (struct map_session_data *) bl)
-        ret = 20 + ((struct map_session_data *) bl)->def_ele;   // 防御属性Lv1
 
     if (sc_data)
     {
         if (sc_data[SC_FREEZE].timer != -1) // 凍結
-            ret = 21;
+            ret = LevelElement{2, Element::water};
         if (sc_data[SC_STONE].timer != -1 && sc_data[SC_STONE].val2 == 0)
-            ret = 22;
+            ret = LevelElement{2, Element::earth};
     }
 
     return ret;
@@ -877,21 +863,18 @@ int battle_get_party_id(struct block_list *bl)
             return -md->master_id;
         return -md->bl.id;
     }
-    else if (bl->type == BL_SKILL && (struct skill_unit *) bl)
-        return ((struct skill_unit *) bl)->group->party_id;
-    else
-        return 0;
+    return 0;
 }
 
-int battle_get_race(struct block_list *bl)
+Race battle_get_race(struct block_list *bl)
 {
-    nullpo_ret(bl);
+    nullpo_retr(Race::formless, bl);
     if (bl->type == BL_MOB && (struct mob_data *) bl)
         return mob_db[((struct mob_data *) bl)->mob_class].race;
     else if (bl->type == BL_PC && (struct map_session_data *) bl)
-        return 7;
+        return Race::demihuman;
     else
-        return 0;
+        return Race::formless;
 }
 
 MobMode battle_get_mode(struct block_list *bl)
@@ -1072,21 +1055,9 @@ int battle_damage(struct block_list *bl, struct block_list *target,
 
         struct map_session_data *tsd = (struct map_session_data *) target;
 
-        if (tsd && tsd->skilltimer != -1)
-        {                       // 詠唱妨害
-            // フェンカードや妨害されないスキルかの検査
-            if (!tsd->special_state.no_castcancel
-                && tsd->state.skillcastcancel
-                && !tsd->special_state.no_castcancel2)
-                skill_castcancel(target, 0);
-        }
-
         return pc_damage(bl, tsd, damage);
 
     }
-    else if (target->type == BL_SKILL)
-        return skill_unit_ondamaged((struct skill_unit *) target, bl, damage,
-                                     gettick());
     return 0;
 }
 
@@ -1143,43 +1114,12 @@ int battle_calc_damage(struct block_list *, struct block_list *bl,
                         SkillID, int, BF flag)
 {
     struct mob_data *md = NULL;
-    eptr<struct status_change, StatusChange> sc_data;
-    short *sc_count;
 
     nullpo_ret(bl);
 
     if (bl->type == BL_MOB)
         md = (struct mob_data *) bl;
 
-    sc_data = battle_get_sc_data(bl);
-    sc_count = battle_get_sc_count(bl);
-
-    if (sc_count != NULL && *sc_count > 0)
-    {
-
-        if (sc_data[SC_SAFETYWALL].timer != -1
-            && damage > 0
-            && bool(flag & BF_WEAPON)
-            && bool(flag & BF_SHORT))
-        {
-            // セーフティウォール
-            struct skill_unit *unit =
-                (struct skill_unit *) sc_data[SC_SAFETYWALL].val2;
-            if (unit && unit->alive && (--unit->group->val2) <= 0)
-                skill_delunit(unit);
-            skill_unit_move(bl, gettick(), 1);    // 重ね掛けチェック
-            damage = 0;
-        }
-        if (sc_data[SC_PNEUMA].timer != -1
-            && damage > 0
-            && bool(flag & BF_WEAPON)
-            && bool(flag & BF_LONG))
-        {
-            // ニューマ
-            damage = 0;
-        }
-    }
-
     if (battle_config.skill_min_damage
         || bool(flag & BF_MISC))
     {
@@ -1211,21 +1151,18 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
     int def1 = battle_get_def(target);
     int def2 = battle_get_def2(target);
     int t_vit = battle_get_vit(target);
-    struct Damage wd;
-    int damage, damage2 = 0, type, div_, blewcount =
-        skill_get_blewcount(skill_num, skill_lv);
+    struct Damage wd {};
+    int damage, damage2 = 0;
+    DamageType type;
+    int div_;
     BF flag;
     int ac_flag = 0;
     ATK dmg_lv = ATK::ZERO;
     eptr<struct status_change, StatusChange> sc_data, t_sc_data;
 
-    //return前の処理があるので情報出力部のみ変更
-    if (src == NULL || target == NULL || md == NULL)
-    {
-        nullpo_info(NLP_MARK);
-        memset(&wd, 0, sizeof(wd));
-        return wd;
-    }
+    nullpo_retr(wd, src);
+    nullpo_retr(wd, target);
+    nullpo_retr(wd, md);
 
     sc_data = battle_get_sc_data(src);
 
@@ -1268,7 +1205,7 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
     }
     hitrate = battle_get_hit(src) - flee + 80;
 
-    type = 0;                   // normal
+    type = DamageType::NORMAL;
     div_ = 1;                   // single attack
 
     if (battle_config.enemy_str)
@@ -1309,7 +1246,7 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
         // 敵の判定
     {
         damage += atkmax;
-        type = 0x0a;
+        type = DamageType::CRITICAL;
     }
     else
     {
@@ -1417,7 +1354,7 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
                                t_sc_data[SC_STAN].timer != -1 ||    // スタンは必中
                                t_sc_data[SC_FREEZE].timer != -1 || (t_sc_data[SC_STONE].timer != -1 && t_sc_data[SC_STONE].val2 == 0))))    // 凍結は必中
         hitrate = 1000000;
-    if (type == 0 && MRAND(100) >= hitrate)
+    if (type == DamageType::NORMAL && MRAND(100) >= hitrate)
     {
         damage = damage2 = 0;
         dmg_lv = ATK_FLEE;
@@ -1427,16 +1364,6 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
         dmg_lv = ATK_DEF;
     }
 
-    if (tsd)
-    {
-        int cardfix = 100;
-        if (bool(flag & BF_LONG))
-            cardfix = cardfix * (100 - tsd->long_attack_def_rate) / 100;
-        if (bool(flag & BF_SHORT))
-            cardfix = cardfix * (100 - tsd->near_attack_def_rate) / 100;
-        damage = damage * cardfix / 100;
-    }
-
     if (damage < 0)
         damage = 0;
 
@@ -1445,7 +1372,7 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
         && MRAND(1000) < battle_get_flee2(target))
     {
         damage = 0;
-        type = 0x0b;
+        type = DamageType::FLEE2;
         dmg_lv = ATK_LUCKY;
     }
 
@@ -1455,7 +1382,7 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
             && MRAND(1000) < battle_get_flee2(target))
         {
             damage = 0;
-            type = 0x0b;
+            type = DamageType::FLEE2;
             dmg_lv = ATK_LUCKY;
         }
     }
@@ -1464,9 +1391,6 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
     if (bool(t_mode & MobMode::PLANT) && damage > 0)
         damage = 1;
 
-    if (tsd && tsd->special_state.no_weapon_damage)
-        damage = 0;
-
     damage = battle_calc_damage(src, target, damage, div_,
             skill_num, skill_lv, flag);
 
@@ -1476,7 +1400,6 @@ struct Damage battle_calc_mob_weapon_attack(struct block_list *src,
     wd.div_ = div_;
     wd.amotion = battle_get_amotion(src);
     wd.dmotion = battle_get_dmotion(target);
-    wd.blewcount = blewcount;
     wd.flag = flag;
     wd.dmg_lv = dmg_lv;
     return wd;
@@ -1516,27 +1439,23 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
     int def1 = battle_get_def(target);
     int def2 = battle_get_def2(target);
     int t_vit = battle_get_vit(target);
-    struct Damage wd;
-    int damage, damage2, type, div_, blewcount =
-        skill_get_blewcount(skill_num, skill_lv);
+    struct Damage wd {};
+    int damage, damage2;
+    DamageType type;
+    int div_;
     BF flag;
     ATK dmg_lv = ATK::ZERO;
-    int t_race = 0;
     eptr<struct status_change, StatusChange> sc_data, t_sc_data;
     int atkmax_ = 0, atkmin_ = 0;  //二刀流用
-    int watk, watk_, cardfix, t_ele;
+    int watk, watk_;
     bool da = false;
     int ac_flag = 0;
     int idef_flag = 0, idef_flag_ = 0;
     int target_distance;
 
-    //return前の処理があるので情報出力部のみ変更
-    if (src == NULL || target == NULL || sd == NULL)
-    {
-        nullpo_info(NLP_MARK);
-        memset(&wd, 0, sizeof(wd));
-        return wd;
-    }
+    nullpo_retr(wd, src);
+    nullpo_retr(wd, target);
+    nullpo_retr(wd, sd);
 
     // アタッカー
     sc_data = battle_get_sc_data(src); //ステータス異常
@@ -1548,8 +1467,6 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         tsd = (struct map_session_data *) target;   //tsdに代入(tmdはNULL)
     else if (target->type == BL_MOB)    //対象がMobなら
         tmd = (struct mob_data *) target;   //tmdに代入(tsdはNULL)
-    t_race = battle_get_race(target);  //対象の種族
-    t_ele = battle_get_elem_type(target);  //対象の属性
     MobMode t_mode = battle_get_mode(target);  //対象のMode
     t_sc_data = battle_get_sc_data(target);    //対象のステータス異常
 
@@ -1597,7 +1514,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
     watk = battle_get_atk(src);    //ATK
     watk_ = battle_get_atk_(src);  //ATK左手
 
-    type = 0;                   // normal
+    type = DamageType::NORMAL;
     div_ = 1;                   // single attack
 
     {
@@ -1634,24 +1551,10 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         sd->state.arrow_atk = 1;    //arrow_atk有効化
     }
 
-    // サイズ修正
-    // ペコ騎乗していて、槍で攻撃した場合は中型のサイズ修正を100にする
-    // ウェポンパーフェクション,ドレイクC
-    if (sd->special_state.no_sizefix)
-    {                           //ペコ騎乗していて、槍で中型を攻撃
-        atkmax = watk;
-        atkmax_ = watk_;
-    }
-    else
     {
         atkmax = watk;
         atkmax_ = watk_;
     }
-    if (sd->special_state.no_sizefix)
-    {                           // ウェポンパーフェクション || ドレイクカード
-        atkmax = watk;
-        atkmax_ = watk_;
-    }
 
     if (atkmin > atkmax && !(sd->state.arrow_atk))
         atkmin = atkmax;        //弓は最低が上回る場合あり
@@ -1699,7 +1602,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         }
         if (sd->state.arrow_atk)
             damage += sd->arrow_atk;
-        type = 0x0a;
+        type = DamageType::CRITICAL;
     }
     else
     {
@@ -1726,48 +1629,6 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
             hitrate += sd->arrow_hit;
         }
 
-        if (def1 < 1000000)
-        {
-            if (sd->def_ratio_atk_ele & (1 << t_ele)
-                || sd->def_ratio_atk_race & (1 << t_race))
-            {
-                damage = (damage * (def1 + def2)) / 100;
-                idef_flag = 1;
-            }
-            if (sd->def_ratio_atk_ele_ & (1 << t_ele)
-                || sd->def_ratio_atk_race_ & (1 << t_race))
-            {
-                damage2 = (damage2 * (def1 + def2)) / 100;
-                idef_flag_ = 1;
-            }
-            if (bool(t_mode & MobMode::BOSS))
-            {
-                if (!idef_flag && sd->def_ratio_atk_race & (1 << 10))
-                {
-                    damage = (damage * (def1 + def2)) / 100;
-                    idef_flag = 1;
-                }
-                if (!idef_flag_ && sd->def_ratio_atk_race_ & (1 << 10))
-                {
-                    damage2 = (damage2 * (def1 + def2)) / 100;
-                    idef_flag_ = 1;
-                }
-            }
-            else
-            {
-                if (!idef_flag && sd->def_ratio_atk_race & (1 << 11))
-                {
-                    damage = (damage * (def1 + def2)) / 100;
-                    idef_flag = 1;
-                }
-                if (!idef_flag_ && sd->def_ratio_atk_race_ & (1 << 11))
-                {
-                    damage2 = (damage2 * (def1 + def2)) / 100;
-                    idef_flag_ = 1;
-                }
-            }
-        }
-
         if (skill_num != SkillID::ZERO && skill_num != SkillID::NEGATIVE)
         {
             flag = (flag & ~BF_SKILLMASK) | BF_SKILL;
@@ -1835,26 +1696,6 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
                 }
                 t_def = def2 * 8 / 10;
                 vitbonusmax = (t_vit / 20) * (t_vit / 20) - 1;
-                if (sd->ignore_def_ele & (1 << t_ele)
-                    || sd->ignore_def_race & (1 << t_race))
-                    idef_flag = 1;
-                if (sd->ignore_def_ele_ & (1 << t_ele)
-                    || sd->ignore_def_race_ & (1 << t_race))
-                    idef_flag_ = 1;
-                if (bool(t_mode & MobMode::BOSS))
-                {
-                    if (sd->ignore_def_race & (1 << 10))
-                        idef_flag = 1;
-                    if (sd->ignore_def_race_ & (1 << 10))
-                        idef_flag_ = 1;
-                }
-                else
-                {
-                    if (sd->ignore_def_race & (1 << 11))
-                        idef_flag = 1;
-                    if (sd->ignore_def_race_ & (1 << 11))
-                        idef_flag_ = 1;
-                }
 
                 if (!idef_flag)
                 {
@@ -1927,7 +1768,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
                                t_sc_data[SC_STAN].timer != -1 ||    // スタンは必中
                                t_sc_data[SC_FREEZE].timer != -1 || (t_sc_data[SC_STONE].timer != -1 && t_sc_data[SC_STONE].val2 == 0))))    // 凍結は必中
         hitrate = 1000000;
-    if (type == 0 && MRAND(100) >= hitrate)
+    if (type == DamageType::NORMAL && MRAND(100) >= hitrate)
     {
         damage = damage2 = 0;
         dmg_lv = ATK_FLEE;
@@ -1937,18 +1778,6 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         dmg_lv = ATK_DEF;
     }
 
-    if (tsd)
-    {                           //対象がPCの場合
-        cardfix = 100;
-        if (bool(flag & BF_LONG))
-            cardfix = cardfix * (100 - tsd->long_attack_def_rate) / 100;    //遠距離攻撃はダメージ減少(ホルンCとか)
-        if (bool(flag & BF_SHORT))
-            cardfix = cardfix * (100 - tsd->near_attack_def_rate) / 100;    //近距離攻撃はダメージ減少(該当無し?)
-        damage = damage * cardfix / 100;    //カード補正によるダメージ減少
-        damage2 = damage2 * cardfix / 100;  //カード補正による左手ダメージ減少
-    }
-//カードによるダメージ減衰処理ここまで
-
     if (damage < 0)
         damage = 0;
     if (damage2 < 0)
@@ -1993,7 +1822,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
     {                           //ダブルアタックが発動しているか
         div_ = 2;
         damage += damage;
-        type = 0x08;
+        type = DamageType::DOUBLED;
     }
 
     if (sd->status.weapon == 16)
@@ -2009,7 +1838,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         && MRAND(1000) < battle_get_flee2(target))
     {
         damage = damage2 = 0;
-        type = 0x0b;
+        type = DamageType::FLEE2;
         dmg_lv = ATK_LUCKY;
     }
 
@@ -2020,7 +1849,7 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
             && MRAND(1000) < battle_get_flee2(target))
         {
             damage = damage2 = 0;
-            type = 0x0b;
+            type = DamageType::FLEE2;
             dmg_lv = ATK_LUCKY;
         }
     }
@@ -2034,10 +1863,6 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
             damage2 = 1;
     }
 
-    //bNoWeaponDamage(設定アイテム無し?)でグランドクロスじゃない場合はダメージが0
-    if (tsd && tsd->special_state.no_weapon_damage)
-        damage = damage2 = 0;
-
     if (damage > 0 || damage2 > 0)
     {
         if (damage2 < 1)        // ダメージ最終修正
@@ -2061,27 +1886,12 @@ struct Damage battle_calc_pc_weapon_attack(struct block_list *src,
         }
     }
 
-    /*              For executioner card [Valaris]              */
-    if (src->type == BL_PC && sd->random_attack_increase_add > 0
-        && sd->random_attack_increase_per > 0 && skill_num == SkillID::ZERO)
-    {
-        if (MRAND(100) < sd->random_attack_increase_per)
-        {
-            if (damage > 0)
-                damage *= sd->random_attack_increase_add / 100;
-            if (damage2 > 0)
-                damage2 *= sd->random_attack_increase_add / 100;
-        }
-    }
-    /*                  End addition                    */
-
     wd.damage = damage;
     wd.damage2 = damage2;
     wd.type = type;
     wd.div_ = div_;
     wd.amotion = battle_get_amotion(src);
     wd.dmotion = battle_get_dmotion(target);
-    wd.blewcount = blewcount;
     wd.flag = flag;
     wd.dmg_lv = dmg_lv;
 
@@ -2098,23 +1908,15 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,
                                          SkillID skill_num, int skill_lv,
                                          int wflag)
 {
-    struct Damage wd;
+    struct Damage wd {};
 
-    //return前の処理があるので情報出力部のみ変更
-    if (src == NULL || target == NULL)
-    {
-        nullpo_info(NLP_MARK);
-        memset(&wd, 0, sizeof(wd));
-        return wd;
-    }
+    nullpo_retr(wd, src);
+    nullpo_retr(wd, target);
 
-    else if (src->type == BL_PC)
+    if (src->type == BL_PC)
         wd = battle_calc_pc_weapon_attack(src, target, skill_num, skill_lv, wflag);    // weapon breaking [Valaris]
     else if (src->type == BL_MOB)
-        wd = battle_calc_mob_weapon_attack(src, target, skill_num, skill_lv,
-                                            wflag);
-    else
-        memset(&wd, 0, sizeof(wd));
+        wd = battle_calc_mob_weapon_attack(src, target, skill_num, skill_lv, wflag);
 
     if (battle_config.equipment_breaking && src->type == BL_PC
         && (wd.damage > 0 || wd.damage2 > 0))
@@ -2123,7 +1925,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,
         if (sd->status.weapon && sd->status.weapon != 11)
         {
             int breakrate = 1;
-            if (wd.type == 0x0a)
+            if (wd.type == DamageType::CRITICAL)
                 breakrate *= 2;
             if (MRAND(10000) <
                 breakrate * battle_config.equipment_break_rate / 100
@@ -2139,7 +1941,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,
         && (wd.damage > 0 || wd.damage2 > 0))
     {
         int breakrate = 1;
-        if (wd.type == 0x0a)
+        if (wd.type == DamageType::CRITICAL)
             breakrate *= 2;
         if (MRAND(10000) <
             breakrate * battle_config.equipment_break_rate / 100
@@ -2163,25 +1965,16 @@ struct Damage battle_calc_magic_attack(struct block_list *bl,
 {
     int mdef1 = battle_get_mdef(target);
     int mdef2 = battle_get_mdef2(target);
-    int matk1, matk2, damage = 0, div_ = 1, blewcount =
-        skill_get_blewcount(skill_num, skill_lv), rdamage = 0;
-    struct Damage md;
+    int matk1, matk2, damage = 0, div_ = 1;
+    struct Damage md {};
     int normalmagic_flag = 1;
-    int t_ele = 0, t_race = 7, cardfix;
-    struct map_session_data *sd = NULL, *tsd = NULL;
+    struct map_session_data *sd = NULL;
 
-    //return前の処理があるので情報出力部のみ変更
-    if (bl == NULL || target == NULL)
-    {
-        nullpo_info(NLP_MARK);
-        memset(&md, 0, sizeof(md));
-        return md;
-    }
+    nullpo_retr(md, bl);
+    nullpo_retr(md, target);
 
     matk1 = battle_get_matk1(bl);
     matk2 = battle_get_matk2(bl);
-    t_ele = battle_get_elem_type(target);
-    t_race = battle_get_race(target);
     MobMode t_mode = battle_get_mode(target);
 
 #define MATK_FIX( a,b ) { matk1=matk1*(a)/(b); matk2=matk2*(a)/(b); }
@@ -2193,8 +1986,6 @@ struct Damage battle_calc_magic_attack(struct block_list *bl,
             MATK_FIX(sd->matk_rate, 100);
         sd->state.arrow_atk = 0;
     }
-    if (target->type == BL_PC)
-        tsd = (struct map_session_data *) target;
 
     BF aflag = BF_MAGIC | BF_LONG | BF_SKILL;
 
@@ -2205,22 +1996,7 @@ struct Damage battle_calc_magic_attack(struct block_list *bl,
             damage = matk2 + MRAND((matk1 - matk2 + 1));
         else
             damage = matk2;
-        if (sd)
-        {
-            if (sd->ignore_mdef_ele & (1 << t_ele)
-                || sd->ignore_mdef_race & (1 << t_race))
-                imdef_flag = 1;
-            if (bool(t_mode & MobMode::BOSS))
-            {
-                if (sd->ignore_mdef_race & (1 << 10))
-                    imdef_flag = 1;
-            }
-            else
-            {
-                if (sd->ignore_mdef_race & (1 << 11))
-                    imdef_flag = 1;
-            }
-        }
+
         if (!imdef_flag)
         {
             if (battle_config.magic_defense_type)
@@ -2239,12 +2015,6 @@ struct Damage battle_calc_magic_attack(struct block_list *bl,
             damage = 1;
     }
 
-    if (tsd)
-    {
-        cardfix = 100;
-        cardfix = cardfix * (100 - tsd->magic_def_rate) / 100;
-        damage = damage * cardfix / 100;
-    }
     if (damage < 0)
         damage = 0;
 
@@ -2257,38 +2027,14 @@ struct Damage battle_calc_magic_attack(struct block_list *bl,
     if (bool(t_mode & MobMode::PLANT) && damage > 0)
         damage = 1;
 
-    if (tsd && tsd->special_state.no_magic_damage)
-    {
-        if (battle_config.gtb_pvp_only != 0)
-        {                       // [MouseJstr]
-            if (map[target->m].flag.pvp
-                && target->type == BL_PC)
-                damage = (damage * (100 - battle_config.gtb_pvp_only)) / 100;
-        }
-        else
-            damage = 0;         // 黄 金蟲カード(魔法ダメージ0)
-    }
-
     damage = battle_calc_damage(bl, target, damage, div_, skill_num, skill_lv, aflag); // 最終修正
 
-    /* magic_damage_return by [AppleGirl] and [Valaris]     */
-    if (target->type == BL_PC && tsd && tsd->magic_damage_return > 0)
-    {
-        rdamage += damage * tsd->magic_damage_return / 100;
-        if (rdamage < 1)
-            rdamage = 1;
-        clif_damage(target, bl, gettick(), 0, 0, rdamage, 0, 0, 0);
-        battle_damage(target, bl, rdamage, 0);
-    }
-    /*          end magic_damage_return         */
-
     md.damage = damage;
     md.div_ = div_;
     md.amotion = battle_get_amotion(bl);
     md.dmotion = battle_get_dmotion(target);
     md.damage2 = 0;
-    md.type = 0;
-    md.blewcount = blewcount;
+    md.type = DamageType::NORMAL;
     md.flag = aflag;
 
     return md;
@@ -2303,22 +2049,15 @@ struct Damage battle_calc_misc_attack(struct block_list *bl,
                                        struct block_list *target,
                                        SkillID skill_num, int skill_lv, int)
 {
-    int cardfix;
-    struct map_session_data *sd = NULL, *tsd = NULL;
-    int damage = 0, div_ = 1, blewcount =
-        skill_get_blewcount(skill_num, skill_lv);
-    struct Damage md;
+    struct map_session_data *sd = NULL;
+    int damage = 0, div_ = 1;
+    struct Damage md {};
     int damagefix = 1;
 
     BF aflag = BF_MISC | BF_LONG | BF_SKILL;
 
-    //return前の処理があるので情報出力部のみ変更
-    if (bl == NULL || target == NULL)
-    {
-        nullpo_info(NLP_MARK);
-        memset(&md, 0, sizeof(md));
-        return md;
-    }
+    nullpo_retr(md, bl);
+    nullpo_retr(md, target);
 
     if (bl->type == BL_PC && (sd = (struct map_session_data *) bl))
     {
@@ -2326,9 +2065,6 @@ struct Damage battle_calc_misc_attack(struct block_list *bl,
         sd->state.arrow_atk = 0;
     }
 
-    if (target->type == BL_PC)
-        tsd = (struct map_session_data *) target;
-
     switch (skill_num)
     {
         case NPC_SELFDESTRUCTION:  // 自爆
@@ -2341,15 +2077,6 @@ struct Damage battle_calc_misc_attack(struct block_list *bl,
     {
         if (damage < 1)
             damage = 1;
-
-        if (tsd)
-        {
-            cardfix = 100;
-            cardfix = cardfix * (100 - tsd->misc_def_rate) / 100;
-            damage = damage * cardfix / 100;
-        }
-        if (damage < 0)
-            damage = 0;
     }
 
     div_ = skill_get_num(skill_num, skill_lv);
@@ -2371,8 +2098,7 @@ struct Damage battle_calc_misc_attack(struct block_list *bl,
     md.amotion = battle_get_amotion(bl);
     md.dmotion = battle_get_dmotion(target);
     md.damage2 = 0;
-    md.type = 0;
-    md.blewcount = blewcount;
+    md.type = DamageType::NORMAL;
     md.flag = aflag;
     return md;
 
@@ -2415,11 +2141,10 @@ struct Damage battle_calc_attack(BF attack_type,
  *------------------------------------------
  */
 ATK battle_weapon_attack(struct block_list *src, struct block_list *target,
-                          unsigned int tick, BCT flag)
+                          unsigned int tick, BCT)
 {
     struct map_session_data *sd = NULL;
     eptr<struct status_change, StatusChange> t_sc_data = battle_get_sc_data(target);
-    int damage, rdamage = 0;
     struct Damage wd;
 
     nullpo_retr(ATK::ZERO, src);
@@ -2480,53 +2205,15 @@ ATK battle_weapon_attack(struct block_list *src, struct block_list *target,
                         "MAGIC-ABSORB-DMG %d", reduction);
         }
 
-        if ((damage = wd.damage + wd.damage2) > 0 && src != target)
-        {
-            if (bool(wd.flag & BF_SHORT))
-            {
-                if (target->type == BL_PC)
-                {
-                    struct map_session_data *tsd =
-                        (struct map_session_data *) target;
-                    if (tsd && tsd->short_weapon_damage_return > 0)
-                    {
-                        rdamage +=
-                            damage * tsd->short_weapon_damage_return / 100;
-                        if (rdamage < 1)
-                            rdamage = 1;
-                    }
-                }
-            }
-            else if (bool(wd.flag & BF_LONG))
-            {
-                if (target->type == BL_PC)
-                {
-                    struct map_session_data *tsd =
-                        (struct map_session_data *) target;
-                    if (tsd && tsd->long_weapon_damage_return > 0)
-                    {
-                        rdamage +=
-                            damage * tsd->long_weapon_damage_return / 100;
-                        if (rdamage < 1)
-                            rdamage = 1;
-                    }
-                }
-            }
-
-            if (rdamage > 0)
-                clif_damage(src, src, tick, wd.amotion, 0, rdamage, 1, 4, 0);
-        }
-
         {
             clif_damage(src, target, tick, wd.amotion, wd.dmotion,
                          wd.damage, wd.div_, wd.type, wd.damage2);
             //二刀流左手とカタール追撃のミス表示(無理やり〜)
             if (sd && sd->status.weapon >= 16 && wd.damage2 == 0)
                 clif_damage(src, target, tick + 10, wd.amotion, wd.dmotion,
-                             0, 1, 0, 0);
+                             0, 1, DamageType::NORMAL, 0);
         }
-        if (sd && sd->splash_range > 0 && (wd.damage > 0 || wd.damage2 > 0))
-            skill_castend_damage_id(src, target, SkillID::ZERO, -1, tick, BCT_ZERO);
+
         map_freeblock_lock();
 
         if (src->type == BL_PC)
@@ -2573,46 +2260,6 @@ ATK battle_weapon_attack(struct block_list *src, struct block_list *target,
         }
         if (sd)
         {
-            if (sd->autospell_id != SkillID::ZERO
-                && sd->autospell_id != SkillID::NEGATIVE
-                && sd->autospell_lv > 0
-                && MRAND(100) < sd->autospell_rate)
-            {
-                int skilllv = sd->autospell_lv, i, f = 0, sp;
-                i = MRAND(100);
-                if (i >= 50)
-                    skilllv -= 2;
-                else if (i >= 15)
-                    skilllv--;
-                if (skilllv < 1)
-                    skilllv = 1;
-                sp = skill_get_sp(sd->autospell_id, skilllv) * 2 / 3;
-                if (sd->status.sp >= sp)
-                {
-                    if ((i = skill_get_inf(sd->autospell_id) == 2)
-                        || i == 32)
-                        f = 0;
-                    else
-                    {
-                        switch (skill_get_nk(sd->autospell_id))
-                        {
-                            case 0:
-                            case 2:
-                                f = skill_castend_damage_id(src, target,
-                                        sd->autospell_id, skilllv,
-                                        tick, flag);
-                                break;
-                            case 1:    /* 支援系 */
-                                f = skill_castend_nodamage_id(src, target,
-                                        sd->autospell_id, skilllv,
-                                        tick, flag);
-                                break;
-                        }
-                    }
-                    if (!f)
-                        pc_heal(sd, 0, -sp);
-                }
-            }
             if (bool(wd.flag & BF_WEAPON)
                 && src != target
                 && (wd.damage > 0 || wd.damage2 > 0))
@@ -2643,32 +2290,25 @@ ATK battle_weapon_attack(struct block_list *src, struct block_list *target,
             }
         }
 
-        if (rdamage > 0)
-            battle_damage(target, src, rdamage, 0);
-
         map_freeblock_unlock();
     }
     return wd.dmg_lv;
 }
 
-int battle_check_undead(int race, int element)
+bool battle_check_undead(Race race, Element element)
 {
     if (battle_config.undead_detect_type == 0)
     {
-        if (element == 9)
-            return 1;
+        return element == Element::undead;
     }
     else if (battle_config.undead_detect_type == 1)
     {
-        if (race == 1)
-            return 1;
+        return race == Race::undead;
     }
     else
     {
-        if (element == 9 || race == 1)
-            return 1;
+        return element == Element::undead || race == Race::undead;
     }
-    return 0;
 }
 
 /*==========================================
@@ -2705,46 +2345,10 @@ int battle_check_target(struct block_list *src, struct block_list *target,
             return -1;
     }
 
-    if (src->type == BL_SKILL && target->type == BL_SKILL)  // 対象がスキルユニットなら無条件肯定
-        return -1;
-
     if (target->type == BL_PC
         && ((struct map_session_data *) target)->invincible_timer != -1)
         return -1;
 
-    if (target->type == BL_SKILL)
-    {
-        switch (((struct skill_unit *) target)->group->unit_id)
-        {
-            case 0x8d:
-            case 0x8f:
-            case 0x98:
-                return 0;
-        }
-    }
-
-    // スキルユニットの場合、親を求める
-    if (src->type == BL_SKILL)
-    {
-        int inf2 =
-            skill_get_inf2(((struct skill_unit *) src)->group->skill_id);
-        if ((ss =
-             map_id2bl(((struct skill_unit *) src)->group->src_id)) == NULL)
-            return -1;
-        if (ss->prev == NULL)
-            return -1;
-        if (inf2 & 0x80 && (map[src->m].flag.pvp || pc_iskiller((struct map_session_data *) src, (struct map_session_data *) target)) &&   // [MouseJstr]
-            !(target->type == BL_PC
-              && pc_isinvisible((struct map_session_data *) target)))
-            return 0;
-        if (ss == target)
-        {
-            if (inf2 & 0x100)
-                return 0;
-            if (inf2 & 0x200)
-                return -1;
-        }
-    }
     // Mobでmaster_idがあってspecial_mob_aiなら、召喚主を求める
     if (src->type == BL_MOB)
     {
@@ -2809,16 +2413,11 @@ int battle_check_target(struct block_list *src, struct block_list *target,
 
     if (ss->type == BL_PC && target->type == BL_PC)
     {                           // 両方PVPモードなら否定(敵)
-        struct skill_unit *su = NULL;
-        if (src->type == BL_SKILL)
-            su = (struct skill_unit *) src;
         if (map[ss->m].flag.pvp
             || pc_iskiller((struct map_session_data *) ss,
                             (struct map_session_data *) target))
         {                       // [MouseJstr]
-            if (su && su->group->target_flag == BCT_NOENEMY)
-                return 1;
-            else if (battle_config.pk_mode)
+            if (battle_config.pk_mode)
                 return 1;       // prevent novice engagement in pk_mode [Valaris]
             else if (map[ss->m].flag.pvp_noparty && s_p > 0 && t_p > 0
                      && s_p == t_p)
diff --git a/src/map/battle.hpp b/src/map/battle.hpp
index 56b3a9f..c4b4601 100644
--- a/src/map/battle.hpp
+++ b/src/map/battle.hpp
@@ -3,6 +3,7 @@
 
 #include "battle.t.hpp"
 
+#include "magic-interpreter.t.hpp"
 #include "map.t.hpp"
 #include "skill.t.hpp"
 
@@ -10,9 +11,9 @@
 struct Damage
 {
     int damage, damage2;
-    int type, div_;
+    DamageType type;
+    int div_;
     int amotion, dmotion;
-    int blewcount;
     BF flag;
     ATK dmg_lv;
 };
@@ -43,7 +44,7 @@ ATK battle_weapon_attack(struct block_list *bl, struct block_list *target,
 
 int battle_is_unarmed(struct block_list *bl);
 int battle_get_class(struct block_list *bl);
-int battle_get_dir(struct block_list *bl);
+DIR battle_get_dir(struct block_list *bl);
 int battle_get_lv(struct block_list *bl);
 int battle_get_range(struct block_list *bl);
 int battle_get_hp(struct block_list *bl);
@@ -62,10 +63,14 @@ int battle_get_speed(struct block_list *bl);
 int battle_get_adelay(struct block_list *bl);
 int battle_get_amotion(struct block_list *bl);
 int battle_get_dmotion(struct block_list *bl);
-int battle_get_element(struct block_list *bl);
-#define battle_get_elem_type(bl)        (battle_get_element(bl)%10)
+LevelElement battle_get_element(struct block_list *bl);
+inline
+Element battle_get_elem_type(struct block_list *bl)
+{
+    return battle_get_element(bl).element;
+}
 int battle_get_party_id(struct block_list *bl);
-int battle_get_race(struct block_list *bl);
+Race battle_get_race(struct block_list *bl);
 MobMode battle_get_mode(struct block_list *bl);
 int battle_get_mexp(struct block_list *bl);
 int battle_get_stat(SP stat_id, struct block_list *bl);
@@ -77,7 +82,7 @@ Opt2 *battle_get_opt2(struct block_list *bl);
 Opt3 *battle_get_opt3(struct block_list *bl);
 Option *battle_get_option(struct block_list *bl);
 
-int battle_check_undead(int race, int element);
+bool battle_check_undead(Race race, Element element);
 int battle_check_target(struct block_list *src, struct block_list *target,
         BCT flag);
 int battle_check_range(struct block_list *src, struct block_list *bl,
diff --git a/src/map/battle.t.hpp b/src/map/battle.t.hpp
index f88fb71..94bdd50 100644
--- a/src/map/battle.t.hpp
+++ b/src/map/battle.t.hpp
@@ -44,6 +44,7 @@ struct BCT
     uint8_t level:4;    // 0x 00 f0 00 00
     uint8_t unused;     // 0x ff 00 00 00
 
+    explicit
     operator bool() { return lo || mid || classic || level || unused; }
 };
 
@@ -93,4 +94,140 @@ BCT BCT_mid_x80 = {0x00, 0x80, 0x0, 0x0, 0x00};
 constexpr
 BCT BCT_highnib = {0x00, 0x00, 0x0, 0xf, 0x00};
 
+enum class Element : uint8_t
+{
+    neutral = 0,
+    water   = 1,
+    earth   = 2,
+    fire    = 3,
+    wind    = 4,
+    poison  = 5,
+    _holy   = 6,
+    dark    = 7,
+    _spirit = 8,
+    undead  = 9,
+
+    COUNT   = 10,
+};
+
+enum class Race : uint8_t
+{
+    formless    = 0,
+    undead      = 1,
+    _brute      = 2,
+    plant       = 3,
+    _insect     = 4,
+    _fish       = 5,
+    _demon      = 6,
+    demihuman   = 7,
+    _angel      = 8,
+    _dragon     = 9,
+    // special - one of these is applied in addition
+    boss        = 10,
+    other       = 11,
+
+    COUNT       = 12,
+};
+
+struct LevelElement
+{
+    uint8_t level;
+    Element element;
+
+    static
+    LevelElement unpack(int packed)
+    {
+        LevelElement le;
+        le.element = static_cast<Element>(packed % 10);
+        le.level = packed / 10;
+        return le;
+    }
+    int pack() const
+    {
+        return level * 10 + static_cast<uint8_t>(element);
+    }
+};
+
+namespace e
+{
+enum class Elements : uint16_t
+{
+    ZERO    = 0x0000,
+    neutral = 1 << 0,
+    water   = 1 << 1,
+    earth   = 1 << 2,
+    fire    = 1 << 3,
+    wind    = 1 << 4,
+    poison  = 1 << 5,
+    _holy   = 1 << 6,
+    dark    = 1 << 7,
+    _spirit = 1 << 8,
+    undead  = 1 << 9,
+};
+ENUM_BITWISE_OPERATORS(Elements)
+
+enum class Races : uint16_t
+{
+    ZERO        = 0x0000,
+    formless    = 1 << 0,
+    undead      = 1 << 1,
+    _brute      = 1 << 2,
+    plant       = 1 << 3,
+    _insect     = 1 << 4,
+    _fish       = 1 << 5,
+    _demon      = 1 << 6,
+    demihuman   = 1 << 7,
+    _angel      = 1 << 8,
+    _dragon     = 1 << 9,
+    // special - one of these is applied in addition
+    boss        = 1 << 10,
+    other       = 1 << 11,
+};
+ENUM_BITWISE_OPERATORS(Races)
+}
+using e::Elements;
+using e::Races;
+
+constexpr
+earray<Elements, Element, Element::COUNT> element_shift //=
+{{
+    Elements::neutral,
+    Elements::water,
+    Elements::earth,
+    Elements::fire,
+    Elements::wind,
+    Elements::poison,
+    Elements::_holy,
+    Elements::dark,
+    Elements::_spirit,
+    Elements::undead,
+}};
+
+constexpr
+earray<Races, Race, Race::COUNT> race_shift //=
+{{
+    Races::formless,
+    Races::undead,
+    Races::_brute,
+    Races::plant,
+    Races::_insect,
+    Races::_fish,
+    Races::_demon,
+    Races::demihuman,
+    Races::_angel,
+    Races::_dragon,
+    Races::boss,
+    Races::other,
+}};
+
+enum class DamageType : uint8_t
+{
+    NORMAL      = 0x00,
+    TAKEITEM    = 0x01,
+    RETURNED    = 0x04,
+    DOUBLED     = 0x08,
+    CRITICAL    = 0x0a,
+    FLEE2       = 0x0b,
+};
+
 #endif // BATTLE_T_HPP
diff --git a/src/map/chat.cpp b/src/map/chat.cpp
index 1f9f433..75b45e9 100644
--- a/src/map/chat.cpp
+++ b/src/map/chat.cpp
@@ -117,7 +117,8 @@ int chat_deletenpcchat(struct npc_data *nd)
     struct chat_data *cd;
 
     nullpo_ret(nd);
-    nullpo_ret(cd = (struct chat_data *) map_id2bl(nd->chat_id));
+    cd = (struct chat_data *) map_id2bl(nd->chat_id);
+    nullpo_ret(cd);
 
     chat_npckickall(cd);
     map_delobject(cd->bl.id, BL_CHAT); // freeまでしてくれる
diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp
index 018c659..302d04c 100644
--- a/src/map/chrif.cpp
+++ b/src/map/chrif.cpp
@@ -752,7 +752,8 @@ int chrif_divorce(int char_id, int partner_id)
         }
     }
 
-    nullpo_ret(sd = map_nick2sd(map_charid2nick(partner_id)));
+    sd = map_nick2sd(map_charid2nick(partner_id));
+    nullpo_ret(sd);
     if (sd->status.partner_id == char_id)
         sd->status.partner_id = 0;
 
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index ba3123a..e719430 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -155,7 +155,6 @@ static
 struct in_addr map_ip;
 static
 int map_port = 5121;
-char talkie_mes[80];
 
 static
 int clif_changelook_towards(struct block_list *bl, LOOK type, int val,
@@ -777,7 +776,7 @@ int clif_set0078(struct map_session_data *sd, unsigned char *buf)
     WBUFW(buf, 26) = sd->status.head_mid;
     WBUFW(buf, 28) = sd->status.hair_color;
     WBUFW(buf, 30) = sd->status.clothes_color;
-    WBUFW(buf, 32) = sd->head_dir;
+    WBUFW(buf, 32) = static_cast<uint8_t>(sd->head_dir);
     WBUFL(buf, 34) = 0 /*guild_id*/;
     WBUFW(buf, 38) = 0 /*guild_emblem_id*/;
     WBUFW(buf, 40) = sd->status.manner;
@@ -785,7 +784,9 @@ int clif_set0078(struct map_session_data *sd, unsigned char *buf)
     WBUFB(buf, 44) = sd->status.karma;
     WBUFB(buf, 45) = sd->sex;
     WBUFPOS(buf, 46, sd->bl.x, sd->bl.y);
-    WBUFB(buf, 48) |= sd->dir & 0x0f;
+    // work around ICE in gcc 4.6
+    uint8_t dir = static_cast<uint8_t>(sd->dir);
+    WBUFB(buf, 48) |= dir;
     WBUFW(buf, 49) = (pc_isGM(sd) == 60 || pc_isGM(sd) == 99) ? 0x80 : 0;
     WBUFB(buf, 51) = sd->state.dead_sit;
     WBUFW(buf, 52) = 0;
@@ -837,7 +838,7 @@ int clif_set007b(struct map_session_data *sd, unsigned char *buf)
     WBUFW(buf, 30) = sd->status.head_mid;
     WBUFW(buf, 32) = sd->status.hair_color;
     WBUFW(buf, 34) = sd->status.clothes_color;
-    WBUFW(buf, 36) = sd->head_dir;
+    WBUFW(buf, 36) = static_cast<uint8_t>(sd->head_dir);
     WBUFL(buf, 38) = 0/*guild_id*/;
     WBUFW(buf, 42) = 0/*guild_emblem_id*/;
     WBUFW(buf, 44) = sd->status.manner;
@@ -874,7 +875,9 @@ int clif_mob0078(struct mob_data *md, unsigned char *buf)
     WBUFW(buf, 14) = md->mob_class;
     // snip: stuff do do with disguise as a PC
     WBUFPOS(buf, 46, md->bl.x, md->bl.y);
-    WBUFB(buf, 48) |= md->dir & 0x0f;
+    // work around ICE in gcc 4.6
+    uint8_t dir = static_cast<uint8_t>(md->dir);
+    WBUFB(buf, 48) |= dir;
     WBUFB(buf, 49) = 5;
     WBUFB(buf, 50) = 5;
     WBUFW(buf, 52) =
@@ -935,7 +938,9 @@ int clif_npc0078(struct npc_data *nd, unsigned char *buf)
     WBUFW(buf, 6) = nd->speed;
     WBUFW(buf, 14) = nd->npc_class;
     WBUFPOS(buf, 46, nd->bl.x, nd->bl.y);
-    WBUFB(buf, 48) |= nd->dir & 0x0f;
+    // work around ICE in gcc 4.6
+    uint8_t dir = static_cast<uint8_t>(nd->dir);
+    WBUFB(buf, 48) |= dir;
     WBUFB(buf, 49) = 5;
     WBUFB(buf, 50) = 5;
 
@@ -1737,7 +1742,8 @@ int clif_storageitemlist(struct map_session_data *sd, struct storage *stor)
             continue;
 
         struct item_data *id;
-        nullpo_ret(id = itemdb_search(stor->storage_[i].nameid));
+        id = itemdb_search(stor->storage_[i].nameid);
+        nullpo_ret(id);
         if (itemdb_isequip2(id))
             continue;
 
@@ -1782,7 +1788,8 @@ int clif_storageequiplist(struct map_session_data *sd, struct storage *stor)
             continue;
 
         struct item_data *id;
-        nullpo_ret(id = itemdb_search(stor->storage_[i].nameid));
+        id = itemdb_search(stor->storage_[i].nameid);
+        nullpo_ret(id);
         if (!itemdb_isequip2(id))
             continue;
         WFIFOW(fd, n * 20 + 4) = i + 1;
@@ -2809,7 +2816,7 @@ int clif_fixpcpos(struct map_session_data *sd)
  */
 int clif_damage(struct block_list *src, struct block_list *dst,
                  unsigned int tick, int sdelay, int ddelay, int damage,
-                 int div, int type, int damage2)
+                 int div, DamageType type, int damage2)
 {
     unsigned char buf[256];
     eptr<struct status_change, StatusChange> sc_data;
@@ -2827,7 +2834,7 @@ int clif_damage(struct block_list *src, struct block_list *dst,
     WBUFL(buf, 18) = ddelay;
     WBUFW(buf, 22) = (damage > 0x7fff) ? 0x7fff : damage;
     WBUFW(buf, 24) = div;
-    WBUFB(buf, 26) = type;
+    WBUFB(buf, 26) = static_cast<uint8_t>(type);
     WBUFW(buf, 27) = damage2;
     clif_send(buf, packet_len_table[0x8a], src, AREA);
 
@@ -2913,8 +2920,6 @@ void clif_getareachar(struct block_list *bl, struct map_session_data *sd)
         case BL_ITEM:
             clif_getareachar_item(sd, (struct flooritem_data *) bl);
             break;
-        case BL_SKILL:
-            break;
         default:
             if (battle_config.error_log)
                 PRINTF("get area char ??? %d\n",
@@ -2954,8 +2959,6 @@ void clif_pcoutsight(struct block_list *bl, struct map_session_data *sd)
         case BL_ITEM:
             clif_clearflooritem((struct flooritem_data *) bl, sd->fd);
             break;
-        case BL_SKILL:
-            break;
     }
 }
 
@@ -2989,8 +2992,6 @@ void clif_pcinsight(struct block_list *bl, struct map_session_data *sd)
         case BL_ITEM:
             clif_getareachar_item(sd, (struct flooritem_data *) bl);
             break;
-        case BL_SKILL:
-            break;
     }
 }
 
@@ -3938,9 +3939,6 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
     if (sd->npc_id != 0 || sd->state.storage_open)
         return;
 
-    if (sd->skilltimer != -1)
-        return;
-
     if (sd->chatID)
         return;
 
@@ -3952,8 +3950,6 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
         || sd->sc_data[SC_ANKLE].timer != -1 //アンクルスネア
         )
         return;
-    if (bool(sd->status.option & Option::HIDE2))
-        return;
 
     if (sd->invincible_timer != -1)
         pc_delinvincibletimer(sd);
@@ -3981,7 +3977,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd)
          && (sd->opt1 != Opt1::ZERO
              || (sd->opt2 != Opt2::ZERO
                  && !(night_flag == 1 && sd->opt2 == Opt2::BLIND))))
-        || sd->skilltimer != -1 || (DIFF_TICK(tick, sd->canact_tick) < 0)
+        || (DIFF_TICK(tick, sd->canact_tick) < 0)
         )
     {
         WFIFOW(fd, 2) = 1;
@@ -4198,12 +4194,13 @@ static
 void clif_parse_ChangeDir(int fd, struct map_session_data *sd)
 {
     unsigned char buf[64];
-    short dir;
 
     nullpo_retv(sd);
 
-//  RFIFOW(fd,2); // Apparently does nothing?
-    dir = RFIFOB(fd, 4);
+    // RFIFOW(fd, 2) is always 0
+    DIR dir = static_cast<DIR>(RFIFOB(fd, 4));
+    if (dir >= DIR::COUNT)
+        return;
 
     if (dir == sd->dir)
         return;
@@ -4213,7 +4210,7 @@ void clif_parse_ChangeDir(int fd, struct map_session_data *sd)
     WBUFW(buf, 0) = 0x9c;
     WBUFL(buf, 2) = sd->bl.id;
     WBUFW(buf, 6) = 0;
-    WBUFB(buf, 8) = dir;
+    WBUFB(buf, 8) = static_cast<uint8_t>(dir);
 
     clif_send(buf, packet_len_table[0x9c], &sd->bl, AREA_WOS);
 
@@ -4274,7 +4271,6 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd)
     }
     if (sd->npc_id != 0
         || bool(sd->opt1)
-        || bool(sd->status.option & Option::HIDE2)
         || sd->state.storage_open)
         return;
 
@@ -4793,150 +4789,6 @@ void clif_parse_SkillUp(int fd, struct map_session_data *sd)
     pc_skillup(sd, SkillID(RFIFOW(fd, 2)));
 }
 
-/*==========================================
- * スキル使用(ID指定)
- *------------------------------------------
- */
-static
-void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
-{
-    int skilllv, lv, target_id;
-    unsigned int tick = gettick();
-
-    nullpo_retv(sd);
-
-    if (sd->chatID || sd->npc_id != 0 || sd->state.storage_open)
-        return;
-
-    skilllv = RFIFOW(fd, 2);
-    SkillID skillnum = SkillID(RFIFOW(fd, 4));
-    target_id = RFIFOL(fd, 6);
-
-    if (sd->skilltimer != -1)
-    {
-        return;
-    }
-    else if (DIFF_TICK(tick, sd->canact_tick) < 0)
-    {
-        clif_skill_fail(sd, skillnum, 4, 0);
-        return;
-    }
-
-    if (sd->sc_data[SC_NOCHAT].timer != -1)
-        return;
-    if (sd->invincible_timer != -1)
-        pc_delinvincibletimer(sd);
-    if (sd->skillitem != SkillID::NEGATIVE && sd->skillitem == skillnum)
-    {
-        if (skilllv != sd->skillitemlv)
-            skilllv = sd->skillitemlv;
-        skill_use_id(sd, target_id, skillnum, skilllv);
-    }
-    else
-    {
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        if ((lv = pc_checkskill(sd, skillnum)) > 0)
-        {
-            if (skilllv > lv)
-                skilllv = lv;
-            skill_use_id(sd, target_id, skillnum, skilllv);
-            if (sd->state.skill_flag)
-                sd->state.skill_flag = 0;
-        }
-    }
-}
-
-/*==========================================
- * スキル使用(場所指定)
- *------------------------------------------
- */
-static
-void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd)
-{
-    int skilllv, lv, x, y;
-    unsigned int tick = gettick();
-    int skillmoreinfo;
-
-    nullpo_retv(sd);
-
-    if (sd->npc_id != 0 || sd->state.storage_open)
-        return;
-    if (sd->chatID)
-        return;
-
-    skillmoreinfo = -1;
-    skilllv = RFIFOW(fd, 2);
-    SkillID skillnum = SkillID(RFIFOW(fd, 4));
-    x = RFIFOW(fd, 6);
-    y = RFIFOW(fd, 8);
-    if (RFIFOW(fd, 0) == 0x190)
-        skillmoreinfo = 10;
-
-    if (skillmoreinfo != -1)
-    {
-        if (pc_issit(sd))
-        {
-            clif_skill_fail(sd, skillnum, 0, 0);
-            return;
-        }
-        memcpy(talkie_mes, RFIFOP(fd, skillmoreinfo), 80);
-    }
-
-    if (sd->skilltimer != -1)
-        return;
-    else if (DIFF_TICK(tick, sd->canact_tick) < 0)
-    {
-        clif_skill_fail(sd, skillnum, 4, 0);
-        return;
-    }
-
-    if (sd->sc_data[SC_NOCHAT].timer != -1)
-        return;
-    if (sd->invincible_timer != -1)
-        pc_delinvincibletimer(sd);
-    if (sd->skillitem != SkillID::NEGATIVE && sd->skillitem == skillnum)
-    {
-        if (skilllv != sd->skillitemlv)
-            skilllv = sd->skillitemlv;
-        skill_use_pos(sd, x, y, skillnum, skilllv);
-    }
-    else
-    {
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        if ((lv = pc_checkskill(sd, skillnum)) > 0)
-        {
-            if (skilllv > lv)
-                skilllv = lv;
-            skill_use_pos(sd, x, y, skillnum, skilllv);
-        }
-    }
-}
-
-/*==========================================
- * スキル使用(map指定)
- *------------------------------------------
- */
-static
-void clif_parse_UseSkillMap(int fd, struct map_session_data *sd)
-{
-    nullpo_retv(sd);
-
-    if (sd->chatID)
-        return;
-
-    if (sd->npc_id != 0
-        || sd->sc_data[SC_NOCHAT].timer != -1)
-        return;
-
-    if (sd->invincible_timer != -1)
-        pc_delinvincibletimer(sd);
-
-    SkillID skill_id = SkillID(RFIFOW(fd, 2));
-    skill_castend_map(sd, skill_id, (const char *)RFIFOP(fd, 4));
-}
-
 /*==========================================
  *
  *------------------------------------------
@@ -5537,15 +5389,15 @@ func_table clif_parse_func_table[0x220] =
         { NULL,                                 0       },      // 110
         { NULL,                                 0       },      // 111
         { clif_parse_SkillUp,                   -1      },      // 112
-        { clif_parse_UseSkillToId,              0       },      // 113
+        { NULL,                                 0       },      // 113
         { NULL,                                 0       },      // 114
         { NULL,                                 0       },      // 115
-        { clif_parse_UseSkillToPos,             0       },      // 116
+        { NULL,                                 0       },      // 116
         { NULL,                                 0       },      // 117
         { clif_parse_StopAttack,                0       },      // 118
         { NULL,                                 0       },      // 119
         { NULL,                                 0       },      // 11a
-        { clif_parse_UseSkillMap,               0       },      // 11b
+        { NULL,                                 0       },      // 11b
         { NULL,                                 0       },      // 11c
         { NULL,                                 0       },      // 11d
         { NULL,                                 0       },      // 11e
@@ -5662,7 +5514,7 @@ func_table clif_parse_func_table[0x220] =
         { NULL,                                 0       },      // 18d
         { NULL,                                 0       },      // 18e
         { NULL,                                 0       },      // 18f
-        { clif_parse_UseSkillToPos,             0       },      // 190
+        { NULL,                                 0       },      // 190
         { NULL,                                 0       },      // 191
         { NULL,                                 0       },      // 192
         { NULL,                                 0       },      // 193
diff --git a/src/map/clif.hpp b/src/map/clif.hpp
index 51ee4aa..bfbca4d 100644
--- a/src/map/clif.hpp
+++ b/src/map/clif.hpp
@@ -5,6 +5,7 @@
 
 #include "../common/const_array.hpp"
 
+#include "battle.t.hpp"
 #include "map.t.hpp"
 #include "pc.t.hpp"
 #include "skill.t.hpp"
@@ -53,8 +54,8 @@ int clif_viewpoint(struct map_session_data *, int, int, int, int, int, int);  //
 int clif_additem(struct map_session_data *, int, int, PickupFail);   //self
 int clif_delitem(struct map_session_data *, int, int);    //self
 int clif_updatestatus(struct map_session_data *, SP);    //self
-int clif_damage(struct block_list *, struct block_list *, unsigned int, int, int, int, int, int, int);    // area
-#define clif_takeitem(src,dst) clif_damage(src,dst,0,0,0,0,0,1,0)
+int clif_damage(struct block_list *, struct block_list *, unsigned int, int, int, int, int, DamageType, int);    // area
+#define clif_takeitem(src,dst) clif_damage(src,dst,0,0,0,0,0,DamageType::TAKEITEM,0)
 int clif_changelook(struct block_list *, LOOK, int);   // area
 void clif_changelook_accessories(struct block_list *bl, struct map_session_data *dst); // area or target; list gloves, boots etc.
 int clif_arrowequip(struct map_session_data *sd, int val);    //self
diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp
index b6a841e..62331f1 100644
--- a/src/map/itemdb.cpp
+++ b/src/map/itemdb.cpp
@@ -525,7 +525,8 @@ void itemdb_final(db_key_t, db_val_t data)
 {
     struct item_data *id;
 
-    nullpo_retv(id = (struct item_data *)data);
+    id = (struct item_data *)data;
+    nullpo_retv(id);
 
     if (id->use_script)
         free(const_cast<ScriptCode *>(id->use_script));
diff --git a/src/map/magic-expr-eval.hpp b/src/map/magic-expr-eval.hpp
index ae9699d..1c4e1d2 100644
--- a/src/map/magic-expr-eval.hpp
+++ b/src/map/magic-expr-eval.hpp
@@ -7,13 +7,6 @@
 
 /* Helper definitions for dealing with functions and operations */
 
-static
-earray<int, DIR, DIR::COUNT> heading_x //=
-{{ 0, -1, -1, -1, 0, 1, 1, 1 }};
-static
-earray<int, DIR, DIR::COUNT> heading_y //=
-{{ 1, 1, 0, -1, -1, -1, 0, 1 }};
-
 int magic_signature_check(const char *opname, const char *funname, const char *signature,
         int args_nr, val_t *args, int line, int column);
 
diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp
index 6ad2cef..9431ecb 100644
--- a/src/map/magic-expr.cpp
+++ b/src/map/magic-expr.cpp
@@ -110,8 +110,6 @@ const char *show_entity(entity_t *entity)
             return ((struct item_data
                      *) (&((struct flooritem_data *) entity)->
                          item_data))->name;
-        case BL_SKILL:
-            return "%skill";
         case BL_SPELL:
             return "%invocation(ERROR:this-should-not-be-an-entity)";
         default:
@@ -629,7 +627,12 @@ BATTLE_GETTER(hp)
 BATTLE_GETTER(mdef)
 BATTLE_GETTER(def)
 BATTLE_GETTER(max_hp)
-BATTLE_GETTER(dir)
+static
+int fun_get_dir(env_t *, int, val_t *result, val_t *args)
+{
+    RESULTDIR = battle_get_dir(ARGENTITY(0));
+    return 0;
+}
 
 #define MMO_GETTER(name)                                        \
 static                                                          \
@@ -833,8 +836,8 @@ static
 int fun_awayfrom(env_t *, int, val_t *result, val_t *args)
 {
     location_t *loc = &ARGLOCATION(0);
-    int dx = heading_x[ARGDIR(1)];
-    int dy = heading_y[ARGDIR(1)];
+    int dx = dirx[ARGDIR(1)];
+    int dy = diry[ARGDIR(1)];
     int distance = ARGINT(2);
     while (distance-- && !map_is_solid(loc->m, loc->x + dx, loc->y + dy))
     {
@@ -971,8 +974,8 @@ void magic_random_location(location_t *dest, area_t *area)
 
                     for (i = 0; i < 10 && map_is_solid(m, x, y); i++)
                     {
-                        x += heading_x[dir];
-                        y += heading_y[dir];
+                        x += dirx[dir];
+                        y += diry[dir];
                     }
 
                     dir = DIR((uint8_t(dir) + 1) % 8);
@@ -1054,14 +1057,14 @@ int fun_status_option(env_t *, int, val_t *result, val_t *args)
 static
 int fun_element(env_t *, int, val_t *result, val_t *args)
 {
-    RESULTINT = battle_get_element(ARGENTITY(0)) % 10;
+    RESULTINT = static_cast<int>(battle_get_element(ARGENTITY(0)).element);
     return 0;
 }
 
 static
 int fun_element_level(env_t *, int, val_t *result, val_t *args)
 {
-    RESULTINT = battle_get_element(ARGENTITY(0)) / 10;
+    RESULTINT = battle_get_element(ARGENTITY(0)).level;
     return 0;
 }
 
diff --git a/src/map/magic-interpreter.t.hpp b/src/map/magic-interpreter.t.hpp
index 49fd3e1..26dc8d9 100644
--- a/src/map/magic-interpreter.t.hpp
+++ b/src/map/magic-interpreter.t.hpp
@@ -64,6 +64,21 @@ enum class DIR : uint8_t
     COUNT,
 };
 
+constexpr
+earray<int, DIR, DIR::COUNT> dirx //=
+{{
+    0, -1, -1, -1, 0, 1, 1, 1,
+}}, diry //=
+{{
+    1, 1, 0, -1, -1, -1, 0, 1,
+}};
+
+constexpr
+bool dir_is_diagonal(DIR d)
+{
+    return static_cast<uint8_t>(d) & 1;
+}
+
 enum class AREA : uint8_t
 {
     LOCATION,
diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp
index f39fc1f..65f6336 100644
--- a/src/map/magic-stmt.cpp
+++ b/src/map/magic-stmt.cpp
@@ -461,8 +461,8 @@ int op_move(env_t *, int, val_t *args)
     entity_t *subject = ARGENTITY(0);
     DIR dir = ARGDIR(1);
 
-    int newx = subject->x + heading_x[dir];
-    int newy = subject->y + heading_y[dir];
+    int newx = subject->x + dirx[dir];
+    int newy = subject->y + diry[dir];
 
     if (!map_is_solid(subject->m, newx, newy))
         entity_warp(subject, subject->m, newx, newy);
@@ -762,7 +762,7 @@ int op_injure(env_t *env, int, val_t *args)
         damage_caused = 0;
 
     // display damage first, because dealing damage may deallocate the target.
-    clif_damage(caster, target, gettick(), 0, 0, damage_caused, 0, 0, 0);
+    clif_damage(caster, target, gettick(), 0, 0, damage_caused, 0, DamageType::NORMAL, 0);
 
     if (caster->type == BL_PC)
     {
diff --git a/src/map/map.cpp b/src/map/map.cpp
index a6aff48..86737a2 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -1084,8 +1084,6 @@ int map_quit(struct map_session_data *sd)
     skill_stop_dancing(&sd->bl, 1);    // ダンス/演奏中断
 
     skill_status_change_clear(&sd->bl, 1); // ステータス異常を解除する
-    skill_clear_unitgroup(&sd->bl);    // スキルユニットグループの削除
-    skill_cleartimerskill(&sd->bl);
     pc_stop_walking(sd, 0);
     pc_stopattack(sd);
     pc_delinvincibletimer(sd);
@@ -1380,100 +1378,73 @@ int map_mapname2ipport(const char *name, struct in_addr *ip, int *port)
     return 0;
 }
 
-/*==========================================
- *
- *------------------------------------------
- */
-int map_check_dir(int s_dir, int t_dir)
+/// Check compatibility of directions.
+/// Directions are compatible if they are at most 45° apart.
+///
+/// @return false if compatible, true if incompatible.
+bool map_check_dir(const DIR s_dir, const DIR t_dir)
 {
     if (s_dir == t_dir)
-        return 0;
-    switch (s_dir)
-    {
-        case 0:
-            if (t_dir == 7 || t_dir == 1 || t_dir == 0)
-                return 0;
-            break;
-        case 1:
-            if (t_dir == 0 || t_dir == 2 || t_dir == 1)
-                return 0;
-            break;
-        case 2:
-            if (t_dir == 1 || t_dir == 3 || t_dir == 2)
-                return 0;
-            break;
-        case 3:
-            if (t_dir == 2 || t_dir == 4 || t_dir == 3)
-                return 0;
-            break;
-        case 4:
-            if (t_dir == 3 || t_dir == 5 || t_dir == 4)
-                return 0;
-            break;
-        case 5:
-            if (t_dir == 4 || t_dir == 6 || t_dir == 5)
-                return 0;
-            break;
-        case 6:
-            if (t_dir == 5 || t_dir == 7 || t_dir == 6)
-                return 0;
-            break;
-        case 7:
-            if (t_dir == 6 || t_dir == 0 || t_dir == 7)
-                return 0;
-            break;
-    }
-    return 1;
+        return false;
+
+    const uint8_t sdir = static_cast<uint8_t>(s_dir);
+    const uint8_t tdir = static_cast<uint8_t>(t_dir);
+    if ((sdir + 1) % 8 == tdir)
+        return false;
+    if (sdir == (tdir + 1) % 8)
+        return false;
+
+    return true;
 }
 
 /*==========================================
  * 彼我の方向を計算
  *------------------------------------------
  */
-int map_calc_dir(struct block_list *src, int x, int y)
+DIR map_calc_dir(struct block_list *src, int x, int y)
 {
-    int dir = 0;
+    DIR dir = DIR_S;
     int dx, dy;
 
-    nullpo_ret(src);
+    nullpo_retr(DIR_S, src);
 
     dx = x - src->x;
     dy = y - src->y;
     if (dx == 0 && dy == 0)
-    {                           // 彼我の場所一致
-        dir = 0;                // 上
+    {
+        dir = DIR_S;
     }
     else if (dx >= 0 && dy >= 0)
-    {                           // 方向的に右上
-        dir = 7;                // 右上
+    {
+        dir = DIR_SE;
         if (dx * 3 - 1 < dy)
-            dir = 0;            // 上
+            dir = DIR_S;
         if (dx > dy * 3)
-            dir = 6;            // 右
+            dir = DIR_E;
     }
     else if (dx >= 0 && dy <= 0)
-    {                           // 方向的に右下
-        dir = 5;                // 右下
+    {
+        dir = DIR_NE;
         if (dx * 3 - 1 < -dy)
-            dir = 4;            // 下
+            dir = DIR_N;
         if (dx > -dy * 3)
-            dir = 6;            // 右
+            dir = DIR_E;
     }
     else if (dx <= 0 && dy <= 0)
-    {                           // 方向的に左下
-        dir = 3;                // 左下
+    {
+        dir = DIR_NW;
         if (dx * 3 + 1 > dy)
-            dir = 4;            // 下
+            dir = DIR_N;
         if (dx < dy * 3)
-            dir = 2;            // 左
+            dir = DIR_W;
     }
     else
-    {                           // 方向的に左上
-        dir = 1;                // 左上
+    {
+        dir = DIR_SW;
         if (-dx * 3 - 1 < dy)
-            dir = 0;            // 上
+            dir = DIR_S;
         if (-dx > dy * 3)
-            dir = 2;            // 左
+            dir = DIR_W;
     }
     return dir;
 }
@@ -1947,9 +1918,6 @@ void cleanup_sub(struct block_list *bl)
         case BL_ITEM:
             map_clearflooritem(bl->id);
             break;
-        case BL_SKILL:
-            skill_delunit((struct skill_unit *) bl);
-            break;
         case BL_SPELL:
             spell_free_invocation((struct invocation *) bl);
             break;
diff --git a/src/map/map.hpp b/src/map/map.hpp
index f9754e3..eab75c4 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -11,6 +11,7 @@
 #include "../common/timer.hpp"
 
 #include "battle.t.hpp"
+#include "magic-interpreter.t.hpp"
 #include "mob.t.hpp"
 #include "script.hpp"   // change to script.t.hpp
 #include "skill.t.hpp"
@@ -26,8 +27,6 @@
 #define MAX_SKILLUNITGROUP 32
 #define MAX_MOBSKILLUNITGROUP 8
 #define MAX_SKILLUNITGROUPTICKSET 128
-#define MAX_SKILLTIMERSKILL 32
-#define MAX_MOBSKILLTIMERSKILL 10
 #define MAX_MOBSKILL 32
 #define MAX_EVENTQUEUE 2
 #define MAX_EVENTTIMER 32
@@ -51,7 +50,7 @@ struct block_list
 struct walkpath_data
 {
     unsigned char path_len, path_pos, path_half;
-    unsigned char path[MAX_WALKPATH];
+    DIR path[MAX_WALKPATH];
 };
 struct script_reg
 {
@@ -74,78 +73,6 @@ struct status_change
 
 struct invocation;
 
-struct skill_unit_group;
-struct skill_unit
-{
-    struct block_list bl;
-
-    struct skill_unit_group *group;
-
-    int limit;
-    int val1, val2;
-    short alive, range;
-};
-struct skill_unit_group
-{
-    int src_id;
-    int party_id;
-    int map, range;
-    BCT target_flag;
-    unsigned int tick;
-    int limit, interval;
-
-    SkillID skill_id;
-    int skill_lv;
-    int val1, val2;
-    char *valstr;
-    int unit_id;
-    int group_id;
-    int unit_count, alive_count;
-    struct skill_unit *unit;
-};
-struct skill_unit_group_tickset
-{
-    unsigned int tick;
-    int group_id;
-};
-struct skill_timerskill
-{
-    int timer;
-    int src_id;
-    int target_id;
-    int map;
-    short x, y;
-    SkillID skill_id;
-    short skill_lv;
-    union sktst
-    {
-        int32_t n;
-        struct { uint16_t x, y; } xy;
-        BF bf;
-
-        static sktst from_n(int32_t n)
-        {
-            sktst r;
-            r.n = n;
-            return r;
-        }
-        static sktst from_xy(uint16_t x, uint16_t y)
-        {
-            sktst r;
-            r.xy.x = x;
-            r.xy.y = y;
-            return r;
-        }
-        static sktst from_bf(BF bf)
-        {
-            sktst r;
-            r.bf = bf;
-            return r;
-        }
-    } type;
-    BCT flag;
-};
-
 struct npc_data;
 struct item_data;
 struct square;
@@ -179,7 +106,6 @@ struct map_session_data
         unsigned gangsterparadise:1;
         unsigned produce_flag:1;
         unsigned make_arrow_flag:1;
-        unsigned potionpitcher_flag:1;
         unsigned storage_open:1;
         unsigned shroud_active:1;
         unsigned shroud_hides_name_talking:1;
@@ -190,16 +116,8 @@ struct map_session_data
     {
         unsigned killer:1;
         unsigned killable:1;
-        unsigned restart_full_recover:1;
-        unsigned no_castcancel:1;
-        unsigned no_castcancel2:1;
-        unsigned no_sizefix:1;
-        unsigned no_magic_damage:1;
-        unsigned no_weapon_damage:1;
-        unsigned no_gemstone:1;
         unsigned unbreakable_weapon:1;
         unsigned unbreakable_armor:1;
-        unsigned infinite_autospell:1;
         unsigned deaf:1;
     } special_state;
     int char_id, login_id1, login_id2, sex;
@@ -216,7 +134,7 @@ struct map_session_data
     Opt1 opt1;
     Opt2 opt2;
     Opt3 opt3;
-    char dir, head_dir;
+    DIR dir, head_dir;
     unsigned int client_tick, server_tick;
     struct walkpath_data walkpath;
     int walktimer;
@@ -257,22 +175,6 @@ struct map_session_data
     //_current slowly approximates _target, and _target is determined by equipment.
 
     short attackrange, attackrange_;
-    int skilltimer;
-    int skilltarget;
-    short skillx, skilly;
-    SkillID skillid;
-    short skilllv;
-    SkillID skillitem;
-    short skillitemlv;
-    SkillID skillid_old;
-    short skilllv_old;
-    SkillID skillid_dance;
-    short skilllv_dance;
-    struct skill_unit_group skillunit[MAX_SKILLUNITGROUP];
-    struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
-    struct skill_timerskill skilltimerskill[MAX_SKILLTIMERSKILL];
-    int cloneskill_id, cloneskill_lv;
-    int potion_hp, potion_sp, potion_per_hp, potion_per_sp;
 
     // [Fate] Used for gradual healing; amount of enqueued regeneration
     struct quick_regeneration quick_regeneration_hp, quick_regeneration_sp;
@@ -288,54 +190,34 @@ struct map_session_data
         inchealspiritsptick;
 // -- moonsoul (new tick for berserk self-damage)
     int berserkdamagetick;
-    int fame;
 
     short weapontype1, weapontype2;
     earray<int, ATTR, ATTR::COUNT> paramb, paramc, parame, paramcard;
     int hit, flee, flee2, aspd, amotion, dmotion;
     int watk, watk2;
     int def, def2, mdef, mdef2, critical, matk1, matk2;
-    int atk_ele, def_ele, star, overrefine;
-    int castrate, hprate, sprate, dsprate;
-    earray<int, BadSC, BadSC::COUNT> addeff, addeff2, reseff;
+    int star, overrefine;
+    int hprate, sprate, dsprate;
     int watk_, watk_2;
-    int atk_ele_, star_, overrefine_;  //二刀流のために追加
+    int star_, overrefine_;  //二刀流のために追加
     int base_atk, atk_rate;
-    int arrow_atk, arrow_ele, arrow_cri, arrow_hit, arrow_range;
-    earray<int, BadSC, BadSC::COUNT> arrow_addeff, arrow_addeff2;
+    int arrow_atk;
+    int arrow_cri, arrow_hit, arrow_range;
     int nhealhp, nhealsp, nshealhp, nshealsp, nsshealhp, nsshealsp;
     int aspd_rate, speed_rate, hprecov_rate, sprecov_rate, critical_def,
         double_rate;
-    int near_attack_def_rate, long_attack_def_rate, magic_def_rate,
-        misc_def_rate;
-    int matk_rate, ignore_def_ele, ignore_def_race, ignore_def_ele_,
-        ignore_def_race_;
-    int ignore_mdef_ele, ignore_mdef_race;
-    int perfect_hit, get_zeny_num;
+    int matk_rate;
+    int perfect_hit;
     int critical_rate, hit_rate, flee_rate, flee2_rate, def_rate, def2_rate,
         mdef_rate, mdef2_rate;
-    int def_ratio_atk_ele, def_ratio_atk_ele_, def_ratio_atk_race,
-        def_ratio_atk_race_;
-    short monster_drop_item_count;
-    short monster_drop_itemid[10];
-    int monster_drop_race[10], monster_drop_itemrate[10];
-    int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add,
-        get_zeny_add_num;
-    short splash_range, splash_add_range;
-    SkillID autospell_id;
-    short autospell_lv, autospell_rate;
+    int double_add_rate, speed_add_rate, aspd_add_rate, perfect_hit_add;
     short hp_drain_rate, hp_drain_per, sp_drain_rate, sp_drain_per;
     short hp_drain_rate_, hp_drain_per_, sp_drain_rate_, sp_drain_per_;
-    int short_weapon_damage_return, long_weapon_damage_return;
     short break_weapon_rate, break_armor_rate;
     short add_steal_rate;
 
     short spiritball, spiritball_old;
     int spirit_timer[MAX_SKILL_LEVEL];
-    int magic_damage_return;   // AppleGirl Was Here
-    int random_attack_increase_add, random_attack_increase_per;    // [Valaris]
-    int perfect_hiding;        // [Valaris]
-    int unbreakable;
 
     int die_counter;
     short doridori_counter;
@@ -369,9 +251,6 @@ struct map_session_data
     char eventqueue[MAX_EVENTQUEUE][50];
     int eventtimer[MAX_EVENTTIMER];
 
-    SkillID last_skillid;
-    int last_skilllv;
-
     struct
     {
         char name[24];
@@ -414,7 +293,8 @@ struct npc_data
 {
     struct block_list bl;
     short n;
-    short npc_class, dir;
+    short npc_class;
+    DIR dir;
     short speed;
     char name[24];
     char exname[24];
@@ -460,7 +340,8 @@ struct mob_data
 {
     struct block_list bl;
     short n;
-    short mob_class, dir;
+    short mob_class;
+    DIR dir;
     MobMode mode;
     short m, x0, y0, xs, ys;
     char name[24];
@@ -468,7 +349,7 @@ struct mob_data
     struct
     {
         MS state;
-        MSS skillstate;
+        MobSkillState skillstate;
         unsigned attackable:1;
         unsigned steal_flag:1;
         unsigned steal_coin_flag:1;
@@ -513,12 +394,9 @@ struct mob_data
     SkillID skillid;
     short skilllv, skillidx;
     unsigned int skilldelay[MAX_MOBSKILL];
-    int def_ele;
+    LevelElement def_ele;
     int master_id, master_dist;
     int exclusion_src, exclusion_party;
-    struct skill_timerskill skilltimerskill[MAX_MOBSKILLTIMERSKILL];
-    struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP];
-    struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
     char npc_event[50];
     // [Fate] mob-specific stats
     earray<unsigned short, mob_stat, mob_stat::LAST> stats;
@@ -630,8 +508,6 @@ extern int night_flag;          // 0=day, 1=night [Yor]
 extern char motd_txt[];
 extern char help_txt[];
 
-extern char talkie_mes[];
-
 extern char wisp_server_name[];
 
 // 鯖全体情報
@@ -717,8 +593,8 @@ int map_getcell(int, int, int);
 int map_setcell(int, int, int, int);
 
 // その他
-int map_check_dir(int s_dir, int t_dir);
-int map_calc_dir(struct block_list *src, int x, int y);
+bool map_check_dir(DIR s_dir, DIR t_dir);
+DIR map_calc_dir(struct block_list *src, int x, int y);
 
 // path.cより
 int path_search(struct walkpath_data *, int, int, int, int, int, int);
diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp
index 0f2e47f..b7abc59 100644
--- a/src/map/map.t.hpp
+++ b/src/map/map.t.hpp
@@ -12,26 +12,13 @@ enum class Option : uint16_t
 {
     ZERO            = 0x0000,
 
-    SIGHT           = 0x0001,
-    // apparently some weaker non-GM hide
-    HIDE2           = 0x0002,
-    CLOAK           = 0x0004,
     // [Fate] This is the GM `@hide' flag
     HIDE            = 0x0040,
-    ORC_HEAD        = 0x0800,
     // [Fate] Complete invisibility to other clients
     INVISIBILITY    = 0x1000,
-    _wedding        = 0x1000,
-    // [Fate] Auto-logging of nearby comments
-    SCRIBE          = 0x2000,
-    CHASEWALK       = 0x4000,
-    sign            = 0x8000,
-
 
     // ?
-    REAL_ANY_HIDE   = HIDE | CLOAK | HIDE2,
-    OLD_ANY_HIDE    = CHASEWALK | CLOAK | HIDE2,
-    MASK            = sign | CHASEWALK | _wedding,
+    REAL_ANY_HIDE   = HIDE,
 };
 enum class Opt1 : uint16_t
 {
@@ -92,8 +79,6 @@ enum class BL : uint8_t
 #define BL_ITEM BL::ITEM
     CHAT,
 #define BL_CHAT BL::CHAT
-    SKILL,
-#define BL_SKILL BL::SKILL
     SPELL,
 #define BL_SPELL BL::SPELL
 };
@@ -179,104 +164,148 @@ enum class ATK
 
 enum class SP : uint16_t
 {
+    // sent to client
     SPEED                       = 0,
 #define SP_SPEED SP::SPEED
 
     // when used as "no stat"
     ZERO = 0,
 
+    // sent to client
     BASEEXP                     = 1,
 #define SP_BASEEXP SP::BASEEXP
+    // sent to client
     JOBEXP                      = 2,
 #define SP_JOBEXP SP::JOBEXP
+#if 0
     KARMA                       = 3,
 #define SP_KARMA SP::KARMA
+#endif
 
+    // sent to client
     HP                          = 5,
 #define SP_HP SP::HP
+    // sent to client
     MAXHP                       = 6,
 #define SP_MAXHP SP::MAXHP
+    // sent to client
     SP                          = 7,
 #define SP_SP SP::SP
+    // sent to client
     MAXSP                       = 8,
 #define SP_MAXSP SP::MAXSP
+    // sent to client
     STATUSPOINT                 = 9,
 #define SP_STATUSPOINT SP::STATUSPOINT
 
+    // sent to client
     BASELEVEL                   = 11,
 #define SP_BASELEVEL SP::BASELEVEL
+    // sent to client
     SKILLPOINT                  = 12,
 #define SP_SKILLPOINT SP::SKILLPOINT
+    // sent to client
     STR                         = 13,
 #define SP_STR SP::STR
+    // sent to client
     AGI                         = 14,
 #define SP_AGI SP::AGI
+    // sent to client
     VIT                         = 15,
 #define SP_VIT SP::VIT
+    // sent to client
     INT                         = 16,
 #define SP_INT SP::INT
+    // sent to client
     DEX                         = 17,
 #define SP_DEX SP::DEX
+    // sent to client
     LUK                         = 18,
 #define SP_LUK SP::LUK
     CLASS                       = 19,
 #define SP_CLASS SP::CLASS
+    // sent to client
     ZENY                        = 20,
 #define SP_ZENY SP::ZENY
     SEX                         = 21,
 #define SP_SEX SP::SEX
+    // sent to client
     NEXTBASEEXP                 = 22,
 #define SP_NEXTBASEEXP SP::NEXTBASEEXP
+    // sent to client
     NEXTJOBEXP                  = 23,
 #define SP_NEXTJOBEXP SP::NEXTJOBEXP
+    // sent to client
     WEIGHT                      = 24,
 #define SP_WEIGHT SP::WEIGHT
+    // sent to client
     MAXWEIGHT                   = 25,
 #define SP_MAXWEIGHT SP::MAXWEIGHT
 
+    // sent to client
     USTR                        = 32,
 #define SP_USTR SP::USTR
+    // sent to client
     UAGI                        = 33,
 #define SP_UAGI SP::UAGI
+    // sent to client
     UVIT                        = 34,
 #define SP_UVIT SP::UVIT
+    // sent to client
     UINT                        = 35,
 #define SP_UINT SP::UINT
+    // sent to client
     UDEX                        = 36,
 #define SP_UDEX SP::UDEX
+    // sent to client
     ULUK                        = 37,
 #define SP_ULUK SP::ULUK
 
+    // sent to client
     ATK1                        = 41,
 #define SP_ATK1 SP::ATK1
+    // sent to client
     ATK2                        = 42,
 #define SP_ATK2 SP::ATK2
+    // sent to client
     MATK1                       = 43,
 #define SP_MATK1 SP::MATK1
+    // sent to client
     MATK2                       = 44,
 #define SP_MATK2 SP::MATK2
+    // sent to client
     DEF1                        = 45,
 #define SP_DEF1 SP::DEF1
+    // sent to client
     DEF2                        = 46,
 #define SP_DEF2 SP::DEF2
+    // sent to client
     MDEF1                       = 47,
 #define SP_MDEF1 SP::MDEF1
+    // sent to client
     MDEF2                       = 48,
 #define SP_MDEF2 SP::MDEF2
+    // sent to client
     HIT                         = 49,
 #define SP_HIT SP::HIT
+    // sent to client
     FLEE1                       = 50,
 #define SP_FLEE1 SP::FLEE1
+    // sent to client
     FLEE2                       = 51,
 #define SP_FLEE2 SP::FLEE2
+    // sent to client
     CRITICAL                    = 52,
 #define SP_CRITICAL SP::CRITICAL
+    // sent to client
     ASPD                        = 53,
 #define SP_ASPD SP::ASPD
 
+    // sent to client
     JOBLEVEL                    = 55,
 #define SP_JOBLEVEL SP::JOBLEVEL
 
+#if 0
     PARTNER                     = 57,
 #define SP_PARTNER SP::PARTNER
     CART                        = 58,
@@ -285,125 +314,213 @@ enum class SP : uint16_t
 #define SP_FAME SP::FAME
     UNBREAKABLE                 = 60,
 #define SP_UNBREAKABLE SP::UNBREAKABLE
+#endif
 
     DEAF                        = 70,
 #define SP_DEAF SP::DEAF
 
+    // sent to client
     GM                          = 500,
 #define SP_GM SP::GM
 
+    // sent to client
     ATTACKRANGE                 = 1000,
 #define SP_ATTACKRANGE SP::ATTACKRANGE
+#if 0
     ATKELE                      = 1001,
 #define SP_ATKELE SP::ATKELE
+#endif
+#if 0
     DEFELE                      = 1002,
 #define SP_DEFELE SP::DEFELE
+#endif
+#if 0
     CASTRATE                    = 1003,
 #define SP_CASTRATE SP::CASTRATE
+#endif
     MAXHPRATE                   = 1004,
 #define SP_MAXHPRATE SP::MAXHPRATE
+#if 0
     MAXSPRATE                   = 1005,
 #define SP_MAXSPRATE SP::MAXSPRATE
+#endif
+#if 0
     SPRATE                      = 1006,
 #define SP_SPRATE SP::SPRATE
+#endif
 
+#if 0
     ADDEFF                      = 1012,
 #define SP_ADDEFF SP::ADDEFF
+#endif
+#if 0
     RESEFF                      = 1013,
 #define SP_RESEFF SP::RESEFF
+#endif
     BASE_ATK                    = 1014,
 #define SP_BASE_ATK SP::BASE_ATK
     ASPD_RATE                   = 1015,
 #define SP_ASPD_RATE SP::ASPD_RATE
     HP_RECOV_RATE               = 1016,
 #define SP_HP_RECOV_RATE SP::HP_RECOV_RATE
+#if 0
     SP_RECOV_RATE               = 1017,
 #define SP_SP_RECOV_RATE SP::SP_RECOV_RATE
+#endif
+#if 0
     SPEED_RATE                  = 1018,
 #define SP_SPEED_RATE SP::SPEED_RATE
+#endif
+#if 0
     CRITICAL_DEF                = 1019,
 #define SP_CRITICAL_DEF SP::CRITICAL_DEF
+#endif
+#if 0
     NEAR_ATK_DEF                = 1020,
 #define SP_NEAR_ATK_DEF SP::NEAR_ATK_DEF
+#endif
+#if 0
     LONG_ATK_DEF                = 1021,
 #define SP_LONG_ATK_DEF SP::LONG_ATK_DEF
+#endif
+#if 0
     DOUBLE_RATE                 = 1022,
 #define SP_DOUBLE_RATE SP::DOUBLE_RATE
+#endif
     DOUBLE_ADD_RATE             = 1023,
 #define SP_DOUBLE_ADD_RATE SP::DOUBLE_ADD_RATE
+#if 0
     MATK                        = 1024,
 #define SP_MATK SP::MATK
+#endif
+#if 0
     MATK_RATE                   = 1025,
 #define SP_MATK_RATE SP::MATK_RATE
+#endif
+#if 0
     IGNORE_DEF_ELE              = 1026,
 #define SP_IGNORE_DEF_ELE SP::IGNORE_DEF_ELE
+#endif
+#if 0
     IGNORE_DEF_RACE             = 1027,
 #define SP_IGNORE_DEF_RACE SP::IGNORE_DEF_RACE
+#endif
+#if 0
     ATK_RATE                    = 1028,
 #define SP_ATK_RATE SP::ATK_RATE
+#endif
     SPEED_ADDRATE               = 1029,
 #define SP_SPEED_ADDRATE SP::SPEED_ADDRATE
+#if 0
     ASPD_ADDRATE                = 1030,
 #define SP_ASPD_ADDRATE SP::ASPD_ADDRATE
+#endif
+#if 0
     MAGIC_ATK_DEF               = 1031,
 #define SP_MAGIC_ATK_DEF SP::MAGIC_ATK_DEF
+#endif
+#if 0
     MISC_ATK_DEF                = 1032,
 #define SP_MISC_ATK_DEF SP::MISC_ATK_DEF
+#endif
+#if 0
     IGNORE_MDEF_ELE             = 1033,
 #define SP_IGNORE_MDEF_ELE SP::IGNORE_MDEF_ELE
+#endif
+#if 0
     IGNORE_MDEF_RACE            = 1034,
 #define SP_IGNORE_MDEF_RACE SP::IGNORE_MDEF_RACE
+#endif
 
+#if 0
     PERFECT_HIT_RATE            = 1038,
 #define SP_PERFECT_HIT_RATE SP::PERFECT_HIT_RATE
+#endif
+#if 0
     PERFECT_HIT_ADD_RATE        = 1039,
 #define SP_PERFECT_HIT_ADD_RATE SP::PERFECT_HIT_ADD_RATE
+#endif
+#if 0
     CRITICAL_RATE               = 1040,
 #define SP_CRITICAL_RATE SP::CRITICAL_RATE
+#endif
+#if 0
     GET_ZENY_NUM                = 1041,
 #define SP_GET_ZENY_NUM SP::GET_ZENY_NUM
+#endif
+#if 0
     ADD_GET_ZENY_NUM            = 1042,
 #define SP_ADD_GET_ZENY_NUM SP::ADD_GET_ZENY_NUM
+#endif
 
+#if 0
     ADD_MONSTER_DROP_ITEM       = 1047,
 #define SP_ADD_MONSTER_DROP_ITEM SP::ADD_MONSTER_DROP_ITEM
+#endif
+#if 0
     DEF_RATIO_ATK_ELE           = 1048,
 #define SP_DEF_RATIO_ATK_ELE SP::DEF_RATIO_ATK_ELE
+#endif
+#if 0
     DEF_RATIO_ATK_RACE          = 1049,
 #define SP_DEF_RATIO_ATK_RACE SP::DEF_RATIO_ATK_RACE
+#endif
+#if 0
     ADD_SPEED                   = 1050,
 #define SP_ADD_SPEED SP::ADD_SPEED
+#endif
+#if 0
     HIT_RATE                    = 1051,
 #define SP_HIT_RATE SP::HIT_RATE
+#endif
+#if 0
     FLEE_RATE                   = 1052,
 #define SP_FLEE_RATE SP::FLEE_RATE
+#endif
+#if 0
     FLEE2_RATE                  = 1053,
 #define SP_FLEE2_RATE SP::FLEE2_RATE
+#endif
     DEF_RATE                    = 1054,
 #define SP_DEF_RATE SP::DEF_RATE
     DEF2_RATE                   = 1055,
 #define SP_DEF2_RATE SP::DEF2_RATE
+#if 0
     MDEF_RATE                   = 1056,
 #define SP_MDEF_RATE SP::MDEF_RATE
+#endif
+#if 0
     MDEF2_RATE                  = 1057,
 #define SP_MDEF2_RATE SP::MDEF2_RATE
+#endif
+#if 0
     SPLASH_RANGE                = 1058,
 #define SP_SPLASH_RANGE SP::SPLASH_RANGE
+#endif
+#if 0
     SPLASH_ADD_RANGE            = 1059,
 #define SP_SPLASH_ADD_RANGE SP::SPLASH_ADD_RANGE
-    AUTOSPELL                   = 1060,
-#define SP_AUTOSPELL SP::AUTOSPELL
+#endif
+
     HP_DRAIN_RATE               = 1061,
 #define SP_HP_DRAIN_RATE SP::HP_DRAIN_RATE
+#if 0
     SP_DRAIN_RATE               = 1062,
 #define SP_SP_DRAIN_RATE SP::SP_DRAIN_RATE
+#endif
+#if 0
     SHORT_WEAPON_DAMAGE_RETURN  = 1063,
 #define SP_SHORT_WEAPON_DAMAGE_RETURN SP::SHORT_WEAPON_DAMAGE_RETURN
+#endif
+#if 0
     LONG_WEAPON_DAMAGE_RETURN   = 1064,
 #define SP_LONG_WEAPON_DAMAGE_RETURN SP::LONG_WEAPON_DAMAGE_RETURN
+#endif
 
+#if 0
     ADDEFF2                     = 1067,
 #define SP_ADDEFF2 SP::ADDEFF2
+#endif
     BREAK_WEAPON_RATE           = 1068,
 #define SP_BREAK_WEAPON_RATE SP::BREAK_WEAPON_RATE
     BREAK_ARMOR_RATE            = 1069,
@@ -412,36 +529,10 @@ enum class SP : uint16_t
 #define SP_ADD_STEAL_RATE SP::ADD_STEAL_RATE
     MAGIC_DAMAGE_RETURN         = 1071,
 #define SP_MAGIC_DAMAGE_RETURN SP::MAGIC_DAMAGE_RETURN
+#if 0
     RANDOM_ATTACK_INCREASE      = 1072,
 #define SP_RANDOM_ATTACK_INCREASE SP::RANDOM_ATTACK_INCREASE
-    ALL_STATS                   = 1073,
-#define SP_ALL_STATS SP::ALL_STATS
-    AGI_VIT                     = 1074,
-#define SP_AGI_VIT SP::AGI_VIT
-    AGI_DEX_STR                 = 1075,
-#define SP_AGI_DEX_STR SP::AGI_DEX_STR
-    PERFECT_HIDE                = 1076,
-#define SP_PERFECT_HIDE SP::PERFECT_HIDE
-
-    RESTART_FULL_RECORVER       = 2000,
-#define SP_RESTART_FULL_RECORVER SP::RESTART_FULL_RECORVER
-    NO_CASTCANCEL               = 2001,
-#define SP_NO_CASTCANCEL SP::NO_CASTCANCEL
-    NO_SIZEFIX                  = 2002,
-#define SP_NO_SIZEFIX SP::NO_SIZEFIX
-    NO_MAGIC_DAMAGE             = 2003,
-#define SP_NO_MAGIC_DAMAGE SP::NO_MAGIC_DAMAGE
-    NO_WEAPON_DAMAGE            = 2004,
-#define SP_NO_WEAPON_DAMAGE SP::NO_WEAPON_DAMAGE
-    NO_GEMSTONE                 = 2005,
-#define SP_NO_GEMSTONE SP::NO_GEMSTONE
-    NO_CASTCANCEL2              = 2006,
-#define SP_NO_CASTCANCEL2 SP::NO_CASTCANCEL2
-
-    UNBREAKABLE_WEAPON          = 2008,
-#define SP_UNBREAKABLE_WEAPON SP::UNBREAKABLE_WEAPON
-    SP_UNBREAKABLE_ARMOR        = 2009,
-#define SP_UNBREAKABLE_ARMOR SP::UNBREAKABLE_ARMOR
+#endif
 };
 
 constexpr
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index f19cd63..47e3e16 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -609,8 +609,7 @@ int mob_can_move(struct mob_data *md)
     nullpo_ret(md);
 
     if (md->canmove_tick > gettick()
-        || (bool(md->opt1) && md->opt1 != Opt1::_stone6)
-        || bool(md->option & Option::HIDE2))
+        || (bool(md->opt1) && md->opt1 != Opt1::_stone6))
         return 0;
     // アンクル中で動けないとか
     if (md->sc_data[SC_ANKLE].timer != -1)
@@ -630,7 +629,7 @@ int calc_next_walk_step(struct mob_data *md)
 
     if (md->walkpath.path_pos >= md->walkpath.path_len)
         return -1;
-    if (md->walkpath.path[md->walkpath.path_pos] & 1)
+    if (dir_is_diagonal(md->walkpath.path[md->walkpath.path_pos]))
         return battle_get_speed(&md->bl) * 14 / 10;
     return battle_get_speed(&md->bl);
 }
@@ -647,8 +646,6 @@ int mob_walk(struct mob_data *md, unsigned int tick, int data)
 {
     int moveblock;
     int i, ctype;
-    static int dirx[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
-    static int diry[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
     int x, y, dx, dy;
 
     nullpo_ret(md);
@@ -670,7 +667,7 @@ int mob_walk(struct mob_data *md, unsigned int tick, int data)
     }
     else
     {
-        if (md->walkpath.path[md->walkpath.path_pos] >= 8)
+        if (md->walkpath.path[md->walkpath.path_pos] >= DIR::COUNT)
             return 1;
 
         x = md->bl.x;
@@ -718,11 +715,6 @@ int mob_walk(struct mob_data *md, unsigned int tick, int data)
                 x + AREA_SIZE, y + AREA_SIZE,
                 -dx, -dy, BL_PC);
         md->state.state = MS_IDLE;
-
-        if (bool(md->option & Option::CLOAK))
-            skill_check_cloaking(&md->bl);
-
-        skill_unit_move(&md->bl, tick, 1); // Inspection of a skill unit
     }
     if ((i = calc_next_walk_step(md)) > 0)
     {
@@ -751,7 +743,7 @@ int mob_check_attack(struct mob_data *md)
     struct mob_data *tmd = NULL;
 
     MobMode mode;
-    int race, range;
+    int range;
 
     nullpo_ret(md);
 
@@ -762,8 +754,7 @@ int mob_check_attack(struct mob_data *md)
     if (md->skilltimer != -1)
         return 0;
 
-    if (bool(md->opt1)
-        || bool(md->option & Option::HIDE2))
+    if (bool(md->opt1))
         return 0;
 
     if ((tbl = map_id2bl(md->target_id)) == NULL)
@@ -807,7 +798,7 @@ int mob_check_attack(struct mob_data *md)
     else
         mode = md->mode;
 
-    race = mob_db[md->mob_class].race;
+    Race race = mob_db[md->mob_class].race;
     if (!bool(mode & MobMode::CAN_ATTACK))
     {
         md->target_id = 0;
@@ -816,9 +807,9 @@ int mob_check_attack(struct mob_data *md)
     }
     if (tsd
         && !bool(mode & MobMode::BOSS)
-        && ((pc_ishiding(tsd) || tsd->state.gangsterparadise)
-            && race != 4
-            && race != 6))
+        && (tsd->state.gangsterparadise
+            && race != Race::_insect
+            && race != Race::_demon))
     {
         md->target_id = 0;
         md->state.attackable = false;
@@ -865,7 +856,7 @@ int mob_attack(struct mob_data *md, unsigned int tick, int)
     //clif_fixmobpos(md);
 
     md->state.skillstate = MSS_ATTACK;
-    if (mobskill_use(md, tick, MSC::NEVER_EQUAL))
+    if (mobskill_use(md, tick, MobSkillCondition::NEVER_EQUAL))
         return 0;
 
     md->target_lv = battle_weapon_attack(&md->bl, tbl, tick, BCT_ZERO);
@@ -957,10 +948,7 @@ int mob_changestate(struct mob_data *md, MS state, int type)
             md->last_deadtime = gettick();
             // Since it died, all aggressors' attack to this mob is stopped.
             clif_foreachclient(std::bind(mob_stopattacked, ph::_1, md->bl.id));
-            skill_unit_out_all(&md->bl, gettick(), 1);
             skill_status_change_clear(&md->bl, 2); // The abnormalities in status are canceled.
-            skill_clear_unitgroup(&md->bl);    // All skill unit groups are deleted.
-            skill_cleartimerskill(&md->bl);
             if (md->deletetimer != -1)
                 delete_timer(md->deletetimer, mob_timer_delete);
             md->deletetimer = -1;
@@ -982,19 +970,16 @@ void mob_timer(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
 {
     struct mob_data *md;
     struct block_list *bl;
-
-    if ((bl = map_id2bl(id)) == NULL)
+    bl = map_id2bl(id);
+    if (bl == NULL)
     {                           //攻撃してきた敵がもういないのは正常のようだ
         return;
     }
 
-    if (!bl || bl->type == BL_NUL || bl->type != BL_MOB)
+    if (bl->type == BL_NUL || bl->type != BL_MOB)
         return;
 
-    nullpo_retv(md = (struct mob_data *) bl);
-
-    if (md->bl.type == BL_NUL || md->bl.type != BL_MOB)
-        return;
+    md = (struct mob_data *) bl;
 
     if (md->timer != tid)
     {
@@ -1109,7 +1094,8 @@ int mob_setdelayspawn(int id)
     if (!bl || bl->type == BL_NUL || bl->type != BL_MOB)
         return -1;
 
-    nullpo_retr(-1, md = (struct mob_data *) bl);
+    md = (struct mob_data *) bl;
+    nullpo_retr(-1, md);
 
     if (!md || md->bl.type != BL_MOB)
         return -1;
@@ -1159,12 +1145,14 @@ int mob_spawn(int id)
     struct mob_data *md;
     struct block_list *bl;
 
-    nullpo_retr(-1, bl = map_id2bl(id));
+    bl = map_id2bl(id);
+    nullpo_retr(-1, bl);
 
     if (!bl || bl->type == BL_NUL || bl->type != BL_MOB)
         return -1;
 
-    nullpo_retr(-1, md = (struct mob_data *) bl);
+    md = (struct mob_data *) bl;
+    nullpo_retr(-1, md);
 
     if (!md || md->bl.type == BL_NUL || md->bl.type != BL_MOB)
         return -1;
@@ -1173,7 +1161,6 @@ int mob_spawn(int id)
     if (md->bl.prev != NULL)
     {
 //      clif_clearchar_area(&md->bl,3);
-        skill_unit_out_all(&md->bl, gettick(), 1);
         map_delblock(&md->bl);
     }
 
@@ -1207,7 +1194,7 @@ int mob_spawn(int id)
 
     md->to_x = md->bl.x = x;
     md->to_y = md->bl.y = y;
-    md->dir = 0;
+    md->dir = DIR_S;
 
     map_addblock(&md->bl);
 
@@ -1245,9 +1232,6 @@ int mob_spawn(int id)
         memset(md->lootitem, 0, sizeof(*md->lootitem));
     md->lootitem_count = 0;
 
-    for (int i = 0; i < MAX_MOBSKILLTIMERSKILL; i++)
-        md->skilltimerskill[i].timer = -1;
-
     for (StatusChange i : erange(StatusChange(), MAX_STATUSCHANGE))
     {
         md->sc_data[i].timer = -1;
@@ -1260,9 +1244,6 @@ int mob_spawn(int id)
     md->opt3 = Opt3::ZERO;
     md->option = Option::ZERO;
 
-    memset(md->skillunit, 0, sizeof(md->skillunit));
-    memset(md->skillunittick, 0, sizeof(md->skillunittick));
-
     md->hp = battle_get_max_hp(&md->bl);
     if (md->hp <= 0)
     {
@@ -1416,14 +1397,13 @@ int mob_target(struct mob_data *md, struct block_list *bl, int dist)
     struct map_session_data *sd;
     eptr<struct status_change, StatusChange> sc_data;
     MobMode mode;
-    int race;
 
     nullpo_ret(md);
     nullpo_ret(bl);
 
     sc_data = battle_get_sc_data(bl);
     Option *option = battle_get_option(bl);
-    race = mob_db[md->mob_class].race;
+    Race race = mob_db[md->mob_class].race;
 
     if (md->mode == MobMode::ZERO)
     {
@@ -1445,16 +1425,17 @@ int mob_target(struct mob_data *md, struct block_list *bl, int dist)
 
     // Coercion is exerted if it is MVPMOB.
     if (bool(mode & MobMode::BOSS)
-        || ((option != NULL && !bool(*option & (Option::CLOAK | Option::HIDE2)))
-            || race == 4
-            || race == 6))
+        || (option != NULL
+            || race == Race::_insect
+            || race == Race::_demon))
     {
         if (bl->type == BL_PC)
         {
-            nullpo_ret(sd = (struct map_session_data *) bl);
+            sd = (struct map_session_data *) bl;
+            nullpo_ret(sd);
             if (sd->invincible_timer != -1 || pc_isinvisible(sd))
                 return 0;
-            if (!bool(mode & MobMode::BOSS) && race != 4 && race != 6
+            if (!bool(mode & MobMode::BOSS) && race != Race::_insect && race != Race::_demon
                 && sd->state.gangsterparadise)
                 return 0;
         }
@@ -1482,7 +1463,7 @@ void mob_ai_sub_hard_activesearch(struct block_list *bl,
     struct map_session_data *tsd = NULL;
     struct mob_data *tmd = NULL;
     MobMode mode;
-    int race, dist;
+    int dist;
 
     nullpo_retv(bl);
     nullpo_retv(smd);
@@ -1507,7 +1488,7 @@ void mob_ai_sub_hard_activesearch(struct block_list *bl,
     // アクティブでターゲット射程内にいるなら、ロックする
     if (bool(mode & MobMode::AGGRESSIVE))
     {
-        race = mob_db[smd->mob_class].race;
+        Race race = mob_db[smd->mob_class].race;
         //対象がPCの場合
         if (tsd &&
             !pc_isdead(tsd) &&
@@ -1518,10 +1499,9 @@ void mob_ai_sub_hard_activesearch(struct block_list *bl,
              distance(smd->bl.x, smd->bl.y, tsd->bl.x, tsd->bl.y)) < 9)
         {
             if (bool(mode & MobMode::BOSS)
-                || ((!pc_ishiding(tsd)
-                        && !tsd->state.gangsterparadise)
-                    || race == 4
-                    || race == 6))
+                || (!tsd->state.gangsterparadise
+                    || race == Race::_insect
+                    || race == Race::_demon))
             {                   // 妨害がないか判定
                 if (mob_can_reach(smd, bl, 12) &&  // 到達可能性判定
                     MRAND(1000) < 1000 / (++(*pcc)))
@@ -1632,7 +1612,7 @@ int mob_ai_sub_hard_slavemob(struct mob_data *md, unsigned int tick)
     struct mob_data *mmd = NULL;
     struct block_list *bl;
     MobMode mode;
-    int race, old_dist;
+    int old_dist;
 
     nullpo_ret(md);
 
@@ -1733,11 +1713,11 @@ int mob_ai_sub_hard_slavemob(struct mob_data *md, unsigned int tick)
             && !pc_isinvisible(sd))
         {
 
-            race = mob_db[md->mob_class].race;
+            Race race = mob_db[md->mob_class].race;
             if (bool(mode & MobMode::BOSS)
-                || ((!pc_ishiding(sd) && !sd->state.gangsterparadise)
-                    || race == 4
-                    || race == 6))
+                || (!sd->state.gangsterparadise
+                    || race == Race::_insect
+                    || race == Race::_demon))
             {                   // 妨害がないか判定
 
                 md->target_id = sd->bl.id;
@@ -1787,7 +1767,8 @@ int mob_randomwalk(struct mob_data *md, int tick)
         if (d < 5)
             d = 5;
         for (i = 0; i < retrycount; i++)
-        {                       // Search of a movable place
+        {
+            // Search of a movable place
             int r = mt_random();
             x = md->bl.x + r % (d * 2 + 1) - d;
             y = md->bl.y + r / (d * 2 + 1) % (d * 2 + 1) - d;
@@ -1811,8 +1792,9 @@ int mob_randomwalk(struct mob_data *md, int tick)
             }
         }
         for (i = c = 0; i < md->walkpath.path_len; i++)
-        {                       // The next walk start time is calculated.
-            if (md->walkpath.path[i] & 1)
+        {
+            // The next walk start time is calculated.
+            if (dir_is_diagonal(md->walkpath.path[i]))
                 c += speed * 14 / 10;
             else
                 c += speed;
@@ -1838,7 +1820,6 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
     int i, dx, dy, ret, dist;
     int attack_type = 0;
     MobMode mode;
-    int race;
 
     nullpo_retv(bl);
     md = (struct mob_data *) bl;
@@ -1859,7 +1840,7 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
     else
         mode = md->mode;
 
-    race = mob_db[md->mob_class].race;
+    Race race = mob_db[md->mob_class].race;
 
     // Abnormalities
     if ((bool(md->opt1) && md->opt1 != Opt1::_stone6)
@@ -1967,9 +1948,9 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
                                   tbl->y)) >= md->min_chase)
                     mob_unlocktarget(md, tick);    // 別マップか、視界外
                 else if (tsd && !bool(mode & MobMode::BOSS)
-                         && ((pc_ishiding(tsd)
-                               || tsd->state.gangsterparadise) && race != 4
-                              && race != 6))
+                         && (tsd->state.gangsterparadise
+                             && race != Race::_insect
+                             && race != Race::_demon))
                     mob_unlocktarget(md, tick);    // スキルなどによる策敵妨害
                 else if (!battle_check_range(&md->bl, tbl, mob_db[md->mob_class].range))
                 {
@@ -1982,7 +1963,7 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
                     if (!mob_can_move(md)) // 動けない状態にある
                         return;
                     md->state.skillstate = MSS_CHASE;   // 突撃時スキル
-                    mobskill_use(md, tick, MSC::ANY);
+                    mobskill_use(md, tick, MobSkillCondition::ANY);
 //                  if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tsd->bl.x,tsd->bl.y)<2) )
                     if (md->timer != -1 && md->state.state != MS_ATTACK
                         && (DIFF_TICK(md->next_walktime, tick) < 0
@@ -2086,7 +2067,7 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
                     if (!mob_can_move(md)) // 動けない状態にある
                         return;
                     md->state.skillstate = MSS_LOOT;    // ルート時スキル使用
-                    mobskill_use(md, tick, MSC::ANY);
+                    mobskill_use(md, tick, MobSkillCondition::ANY);
 //                  if(md->timer != -1 && (DIFF_TICK(md->next_walktime,tick)<0 || distance(md->to_x,md->to_y,tbl->x,tbl->y)<2) )
                     if (md->timer != -1 && md->state.state != MS_ATTACK
                         && (DIFF_TICK(md->next_walktime, tick) < 0
@@ -2144,7 +2125,7 @@ void mob_ai_sub_hard(struct block_list *bl, unsigned int tick)
     }
 
     // It is skill use at the time of /standby at the time of a walk.
-    if (mobskill_use(md, tick, MSC::ANY))
+    if (mobskill_use(md, tick, MobSkillCondition::ANY))
         return;
 
     // 歩行処理
@@ -2300,7 +2281,8 @@ void mob_delay_item_drop(timer_id, tick_t, custom_id_t id, custom_data_t)
     struct item temp_item;
     PickupFail flag;
 
-    nullpo_retv(ditem = (struct delay_item_drop *) id);
+    ditem = (struct delay_item_drop *) id;
+    nullpo_retv(ditem);
 
     memset(&temp_item, 0, sizeof(temp_item));
     temp_item.nameid = ditem->nameid;
@@ -2339,7 +2321,8 @@ void mob_delay_item_drop2(timer_id, tick_t, custom_id_t id, custom_data_t)
     struct delay_item_drop2 *ditem;
     PickupFail flag;
 
-    nullpo_retv(ditem = (struct delay_item_drop2 *) id);
+    ditem = (struct delay_item_drop2 *) id;
+    nullpo_retv(ditem);
 
     if (battle_config.item_auto_get == 1)
     {
@@ -2500,7 +2483,7 @@ int mob_damage(struct block_list *src, struct mob_data *md, int damage,
         {
             mob_changestate(md, MS_DEAD, 0);
             // It is skill at the time of death.
-            mobskill_use(md, tick, MSC::ANY);
+            mobskill_use(md, tick, MobSkillCondition::ANY);
 
             clif_clearchar_area(&md->bl, 1);
             map_delblock(&md->bl);
@@ -2599,9 +2582,6 @@ int mob_damage(struct block_list *src, struct mob_data *md, int damage,
 
     md->hp -= damage;
 
-    if (bool(md->option & Option::HIDE2))
-        skill_status_change_end(&md->bl, SC_HIDING, -1);
-
     if (md->hp > 0)
     {
         return 0;
@@ -2613,7 +2593,7 @@ int mob_damage(struct block_list *src, struct mob_data *md, int damage,
 
     map_freeblock_lock();
     mob_changestate(md, MS_DEAD, 0);
-    mobskill_use(md, tick, MSC::ANY);
+    mobskill_use(md, tick, MobSkillCondition::ANY);
 
     memset(tmpsd, 0, sizeof(tmpsd));
     memset(pt, 0, sizeof(pt));
@@ -2777,42 +2757,6 @@ int mob_damage(struct block_list *src, struct mob_data *md, int damage,
                 ditem->third_sd = third_sd;
                 add_timer(tick + 500 + i, mob_delay_item_drop, (int) ditem, 0);
             }
-            if (sd && sd->state.attack_type == BF_WEAPON)
-            {
-                for (int i = 0; i < sd->monster_drop_item_count; i++)
-                {
-                    struct delay_item_drop *ditem;
-                    int race = battle_get_race(&md->bl);
-                    if (sd->monster_drop_itemid[i] <= 0)
-                        continue;
-                    if (sd->monster_drop_race[i] & (1 << race) ||
-                        (bool(mob_db[md->mob_class].mode & MobMode::BOSS)
-                         && sd->monster_drop_race[i] & 1 << 10)
-                        || (!bool(mob_db[md->mob_class].mode & MobMode::BOSS)
-                            && sd->monster_drop_race[i] & 1 << 11))
-                    {
-                        if (sd->monster_drop_itemrate[i] <= MRAND(10000))
-                            continue;
-
-                        ditem = (struct delay_item_drop *)
-                            calloc(1, sizeof(struct delay_item_drop));
-                        ditem->nameid = sd->monster_drop_itemid[i];
-                        ditem->amount = 1;
-                        ditem->m = md->bl.m;
-                        ditem->x = md->bl.x;
-                        ditem->y = md->bl.y;
-                        ditem->first_sd = mvp_sd;
-                        ditem->second_sd = second_sd;
-                        ditem->third_sd = third_sd;
-                        add_timer(tick + 520 + i, mob_delay_item_drop,
-                                   (int) ditem, 0);
-                    }
-                }
-                if (sd->get_zeny_num > 0)
-                    pc_getzeny(sd,
-                                mob_db[md->mob_class].lv * 10 +
-                                MRAND((sd->get_zeny_num + 1)));
-            }
             if (md->lootitem)
             {
                 for (int i = 0; i < md->lootitem_count; i++)
@@ -2991,9 +2935,6 @@ int mob_class_change(struct mob_data *md, int *value)
         md->lootitem = (struct item *)
             calloc(LOOTITEM_SIZE, sizeof(struct item));
 
-    skill_clear_unitgroup(&md->bl);
-    skill_cleartimerskill(&md->bl);
-
     clif_clearchar_area(&md->bl, 0);
     clif_spawnmob(md);
 
@@ -3068,7 +3009,6 @@ int mob_warp(struct mob_data *md, int m, int x, int y, int type)
             return 0;
         clif_clearchar_area(&md->bl, type);
     }
-    skill_unit_out_all(&md->bl, gettick(), 1);
     map_delblock(&md->bl);
 
     if (bx > 0 && by > 0)
@@ -3090,7 +3030,7 @@ int mob_warp(struct mob_data *md, int m, int x, int y, int type)
             y = MPRAND(1, (map[m].ys - 2));
         }
     }
-    md->dir = 0;
+    md->dir = DIR_S;
     if (i < 1000)
     {
         md->bl.x = md->to_x = x;
@@ -3370,13 +3310,14 @@ void mobskill_castend_pos(timer_id tid, tick_t tick, custom_id_t id, custom_data
 {
     struct mob_data *md = NULL;
     struct block_list *bl;
-    int range, maxcount;
+    int range;
 
     //mobskill_castend_id同様詠唱したMobが詠唱完了時にもういないというのはありそうなのでnullpoから除外
     if ((bl = map_id2bl(id)) == NULL)
         return;
 
-    nullpo_retv(md = (struct mob_data *) bl);
+    md = (struct mob_data *) bl;
+    nullpo_retv(md);
 
     if (md->bl.type != BL_MOB || md->bl.prev == NULL)
         return;
@@ -3389,23 +3330,6 @@ void mobskill_castend_pos(timer_id tid, tick_t tick, custom_id_t id, custom_data
     if (bool(md->opt1))
         return;
 
-    if (battle_config.monster_land_skill_limit == 1)
-    {
-        maxcount = skill_get_maxcount(md->skillid);
-        if (maxcount > 0)
-        {
-            int i, c;
-            for (i = c = 0; i < MAX_MOBSKILLUNITGROUP; i++)
-            {
-                if (md->skillunit[i].alive_count > 0
-                    && md->skillunit[i].skill_id == md->skillid)
-                    c++;
-            }
-            if (c >= maxcount)
-                return;
-        }
-    }
-
     range = skill_get_range(md->skillid, md->skilllv);
     if (range < 0)
         range = battle_get_range(&md->bl) - (range + 1);
@@ -3433,7 +3357,8 @@ int mobskill_use_id(struct mob_data *md, struct block_list *target,
     int skill_lv;
 
     nullpo_ret(md);
-    nullpo_ret(ms = &mob_db[md->mob_class].skill[skill_idx]);
+    ms = &mob_db[md->mob_class].skill[skill_idx];
+    nullpo_ret(ms);
 
     if (target == NULL && (target = map_id2bl(md->target_id)) == NULL)
         return 0;
@@ -3447,9 +3372,6 @@ int mobskill_use_id(struct mob_data *md, struct block_list *target,
     if (bool(md->opt1))
         return 0;
 
-    if (bool(md->option & Option::HIDE2))
-        return 0;
-
     if (skill_get_inf2(skill_id) & 0x200 && md->bl.id == target->id)
         return 0;
 
@@ -3511,7 +3433,8 @@ int mobskill_use_pos(struct mob_data *md,
     int skill_lv;
 
     nullpo_ret(md);
-    nullpo_ret(ms = &mob_db[md->mob_class].skill[skill_idx]);
+    ms = &mob_db[md->mob_class].skill[skill_idx];
+    nullpo_ret(ms);
 
     if (md->bl.prev == NULL)
         return 0;
@@ -3522,9 +3445,6 @@ int mobskill_use_pos(struct mob_data *md,
     if (bool(md->opt1))
         return 0;
 
-    if (bool(md->option & Option::HIDE2))
-        return 0;
-
     // 射程と障害物チェック
     bl.type = BL_NUL;
     bl.m = md->bl.m;
@@ -3570,100 +3490,20 @@ int mobskill_use_pos(struct mob_data *md,
     return 1;
 }
 
-/*==========================================
- * Friendly Mob whose HP is decreasing by a nearby MOB is looked for.
- *------------------------------------------
- */
-static
-void mob_getfriendhpltmaxrate_sub(struct block_list *bl, struct mob_data *mmd, int rate, struct mob_data **fr)
-{
-    struct mob_data *md;
-
-    nullpo_retv(bl);
-    nullpo_retv(mmd);
-
-    md = (struct mob_data *) bl;
-
-    if (mmd->bl.id == bl->id)
-        return;
-
-    if (md->hp < mob_db[md->mob_class].max_hp * rate / 100)
-        (*fr) = md;
-}
-
-static
-struct mob_data *mob_getfriendhpltmaxrate(struct mob_data *md, int rate)
-{
-    struct mob_data *fr = NULL;
-    const int r = 8;
-
-    nullpo_retr(NULL, md);
-
-    map_foreachinarea(std::bind(mob_getfriendhpltmaxrate_sub, ph::_1, md, rate, &fr),
-            md->bl.m, md->bl.x - r, md->bl.y - r,
-            md->bl.x + r, md->bl.y + r, BL_MOB);
-    return fr;
-}
-
-/*==========================================
- * What a status state suits by nearby MOB is looked for.
- *------------------------------------------
- */
-static
-void mob_getfriendstatus_sub(struct block_list *bl, struct mob_data *mmd, MSC cond1, StatusChange cond2, struct mob_data **fr)
-{
-    struct mob_data *md;
-    int flag = 0;
-
-    nullpo_retv(bl);
-    md = (struct mob_data *) bl;
-
-    if (mmd->bl.id == bl->id)
-        return;
-
-    if (cond2 == StatusChange::ANY_BAD)
-    {
-        for (StatusChange j : MAJOR_STATUS_EFFECTS)
-        {
-            flag = (md->sc_data[j].timer != -1);
-            if (flag)
-                break;
-        }
-    }
-    else
-        flag = (md->sc_data[cond2].timer != -1);
-    if (flag ^ (cond1 == MSC_FRIENDSTATUSOFF))
-        (*fr) = md;
-}
-
-static
-struct mob_data *mob_getfriendstatus(struct mob_data *md,
-        MSC cond1, StatusChange cond2)
-{
-    struct mob_data *fr = NULL;
-    const int r = 8;
-
-    nullpo_ret(md);
-
-    map_foreachinarea(std::bind(mob_getfriendstatus_sub, ph::_1, md, cond1, cond2, &fr),
-            md->bl.m, md->bl.x - r, md->bl.y - r,
-            md->bl.x + r, md->bl.y + r, BL_MOB);
-    return fr;
-}
-
 /*==========================================
  * Skill use judging
  *------------------------------------------
  */
 int mobskill_use(struct mob_data *md, unsigned int tick,
-        MSC event, SkillID skill)
+        MobSkillCondition event, SkillID)
 {
     struct mob_skill *ms;
 //  struct block_list *target=NULL;
     int max_hp;
 
     nullpo_ret(md);
-    nullpo_ret(ms = mob_db[md->mob_class].skill);
+    ms = mob_db[md->mob_class].skill;
+    nullpo_ret(ms);
 
     max_hp = battle_get_max_hp(&md->bl);
 
@@ -3679,17 +3519,16 @@ int mobskill_use(struct mob_data *md, unsigned int tick,
     for (int ii = 0; ii < mob_db[md->mob_class].maxskill; ii++)
     {
         int flag = 0;
-        struct mob_data *fmd = NULL;
 
         // ディレイ中
         if (DIFF_TICK(tick, md->skilldelay[ii]) < ms[ii].delay)
             continue;
 
         // 状態判定
-        if (ms[ii].state != MSS::ANY && ms[ii].state != md->state.skillstate)
+        if (ms[ii].state != MobSkillState::ANY && ms[ii].state != md->state.skillstate)
             continue;
 
-        // Note: these *may* both be MSC::ANY
+        // Note: these *may* both be MobSkillCondition::ANY
         flag = (event == ms[ii].cond1);
         if (!flag)
         {
@@ -3701,54 +3540,15 @@ int mobskill_use(struct mob_data *md, unsigned int tick,
                 case MSC_MYHPLTMAXRATE:    // HP< maxhp%
                     flag = (md->hp < max_hp * ms[ii].cond2i / 100);
                     break;
-                case MSC_MYSTATUSON:   // status[num] on
-                case MSC_MYSTATUSOFF:  // status[num] off
-                    if (ms[ii].cond2sc() == StatusChange::ANY_BAD)
-                    {
-                        for (StatusChange j : MAJOR_STATUS_EFFECTS)
-                        {
-                            flag = (md->sc_data[j].timer != -1);
-                            if (flag)
-                                break;
-                        }
-                    }
-                    else
-                        flag = (md->sc_data[ms[ii].cond2sc()].timer != -1);
-                    flag ^= (ms[ii].cond1 == MSC_MYSTATUSOFF);
-                    break;
-                case MSC_FRIENDHPLTMAXRATE:    // friend HP < maxhp%
-                    flag =
-                        ((fmd =
-                          mob_getfriendhpltmaxrate(md,
-                                                    ms[ii].cond2i)) != NULL);
-                    break;
-                case MSC_FRIENDSTATUSON:   // friend status[num] on
-                case MSC_FRIENDSTATUSOFF:  // friend status[num] off
-                    flag =
-                        ((fmd =
-                          mob_getfriendstatus(md, ms[ii].cond1,
-                                               ms[ii].cond2sc())) != NULL);
-                    break;
                 case MSC_NOTINTOWN:     // Only outside of towns.
                     flag = !map[md->bl.m].flag.town;
                     break;
                 case MSC_SLAVELT:  // slave < num
                     flag = (mob_countslave(md) < ms[ii].cond2i);
                     break;
-                case MSC_ATTACKPCGT:   // attack pc > num
-                    flag = (mob_counttargeted(md, NULL, ATK::ZERO) > ms[ii].cond2i);
-                    break;
                 case MSC_SLAVELE:  // slave <= num
                     flag = (mob_countslave(md) <= ms[ii].cond2i);
                     break;
-                case MSC_ATTACKPCGE:   // attack pc >= num
-                    flag = (mob_counttargeted(md, NULL, ATK::ZERO) >= ms[ii].cond2i);
-                    break;
-                case MSC_SKILLUSED:    // specificated skill used
-                    flag = (event == MSC_SKILLUSED
-                            && (skill == ms[ii].cond2sk()
-                                || ms[ii].cond2sk() == SkillID::ZERO));
-                    break;
             }
         }
 
@@ -3761,22 +3561,11 @@ int mobskill_use(struct mob_data *md, unsigned int tick,
                 // 場所指定
                 struct block_list *bl = NULL;
                 int x = 0, y = 0;
-                if (ms[ii].target <= MST_AROUND)
                 {
-                    if (ms[ii].target == MST_MASTER)
                     {
-                        bl = &md->bl;
-                        if (md->master_id)
-                            bl = map_id2bl(md->master_id);
-                    }
-                    else
-                    {
-                        bl = ((ms[ii].target == MST_TARGET
-                               || ms[ii].target ==
-                               MST_AROUND5) ? map_id2bl(md->
-                                                         target_id)
-                              : (ms[ii].target ==
-                                 MST_FRIEND) ? &fmd->bl : &md->bl);
+                        bl = ms[ii].target == MST_TARGET
+                            ? map_id2bl(md->target_id)
+                            : &md->bl;
                     }
 
                     if (bl)
@@ -3787,72 +3576,16 @@ int mobskill_use(struct mob_data *md, unsigned int tick,
                 }
                 if (x <= 0 || y <= 0)
                     continue;
-                // 自分の周囲
-                if (ms[ii].target >= MST_AROUND1)
-                {
-                    int bx, by, i = 0, c, m = bl->m;
-                    // the enum values for radii are adjacent
-                    int r = int(ms[i].target) - int(MST_AROUND1);
-                    do
-                    {
-                        bx = x + MRAND((r * 2 + 3)) - r;
-                        by = y + MRAND((r * 2 + 3)) - r;
-                    }
-                    while ((bx <= 0 || by <= 0 || bx >= map[m].xs
-                            || by >= map[m].ys
-                            || ((c = read_gat(m, bx, by)) == 1 || c == 5))
-                           && (i++) < 1000);
-                    if (i < 1000)
-                    {
-                        x = bx;
-                        y = by;
-                    }
-                }
-                // 相手の周囲
-                if (ms[ii].target >= MST_AROUND5)
-                {
-                    int bx, by, i = 0, c, m = bl->m;
-                    int r = int(ms[i].target) - int(MST_AROUND5) + 1;
-                    do
-                    {
-                        bx = x + MRAND((r * 2 + 1)) - r;
-                        by = y + MRAND((r * 2 + 1)) - r;
-                    }
-                    while ((bx <= 0 || by <= 0 || bx >= map[m].xs
-                            || by >= map[m].ys
-                            || ((c = read_gat(m, bx, by)) == 1 || c == 5))
-                           && (i++) < 1000);
-                    if (i < 1000)
-                    {
-                        x = bx;
-                        y = by;
-                    }
-                }
                 if (!mobskill_use_pos(md, x, y, ii))
                     return 0;
-
             }
             else
             {
-                if (ms[ii].target == MST_MASTER)
-                {
-                    struct block_list *bl = &md->bl;
-                    if (md->master_id)
-                        bl = map_id2bl(md->master_id);
-
-                    if (bl && !mobskill_use_id(md, bl, ii))
-                        return 0;
-                }
-                // ID指定
-                if (ms[ii].target <= MST_FRIEND)
                 {
                     struct block_list *bl = NULL;
-                    bl = ((ms[ii].target ==
-                           MST_TARGET) ? map_id2bl(md->
-                                                    target_id) : (ms[ii].target
-                                                                  ==
-                                                                  MST_FRIEND)
-                          ? &fmd->bl : &md->bl);
+                    bl = (ms[ii].target == MST_TARGET)
+                        ? map_id2bl(md->target_id)
+                        : &md->bl;
                     if (bl && !mobskill_use_id(md, bl, ii))
                         return 0;
                 }
@@ -3874,13 +3607,14 @@ int mobskill_event(struct mob_data *md, BF flag)
 {
     nullpo_ret(md);
 
-    if (flag == BF::NEGATIVE_1 && mobskill_use(md, gettick(), MSC_CASTTARGETED))
+    if (flag == BF::NEGATIVE_1
+        && mobskill_use(md, gettick(), MobSkillCondition::ANY))
         return 1;
     if (bool(flag & BF_SHORT)
-        && mobskill_use(md, gettick(), MSC_CLOSEDATTACKED))
+        && mobskill_use(md, gettick(), MobSkillCondition::ANY))
         return 1;
     if (bool(flag & BF_LONG)
-        && mobskill_use(md, gettick(), MSC_LONGRANGEATTACKED))
+        && mobskill_use(md, gettick(), MobSkillCondition::ANY))
         return 1;
     return 0;
 }
@@ -3917,9 +3651,9 @@ int mob_makedummymobdb(int mob_class)
     mob_db[mob_class].attrs[ATTR::LUK] = 2;
     mob_db[mob_class].range2 = 10;
     mob_db[mob_class].range3 = 10;
-    mob_db[mob_class].size = 0;
-    mob_db[mob_class].race = 0;
-    mob_db[mob_class].element = 0;
+    mob_db[mob_class].size = 0; // 1
+    mob_db[mob_class].race = Race::formless;
+    mob_db[mob_class].element = LevelElement{0, Element::neutral};
     mob_db[mob_class].mode = MobMode::ZERO;
     mob_db[mob_class].speed = 300;
     mob_db[mob_class].adelay = 1000;
@@ -4038,9 +3772,9 @@ int mob_readdb(void)
             mob_db[mob_class].attrs[ATTR::LUK] = atoi(str[18]);
             mob_db[mob_class].range2 = atoi(str[19]);
             mob_db[mob_class].range3 = atoi(str[20]);
-            mob_db[mob_class].size = atoi(str[21]);
-            mob_db[mob_class].race = atoi(str[22]);
-            mob_db[mob_class].element = atoi(str[23]);
+            mob_db[mob_class].size = atoi(str[21]); // always 1
+            mob_db[mob_class].race = static_cast<Race>(atoi(str[22]));
+            mob_db[mob_class].element = LevelElement::unpack(atoi(str[23]));
             mob_db[mob_class].mode = static_cast<MobMode>(atoi(str[24]));
             mob_db[mob_class].speed = atoi(str[25]);
             mob_db[mob_class].adelay = atoi(str[26]);
@@ -4196,78 +3930,34 @@ int mob_readskilldb(void)
     const struct
     {
         char str[32];
-        MSC id;
+        MobSkillCondition id;
     } cond1[] =
     {
         {"always", MSC_ALWAYS},
         {"myhpltmaxrate", MSC_MYHPLTMAXRATE},
-        {"friendhpltmaxrate", MSC_FRIENDHPLTMAXRATE},
-        {"mystatuson", MSC_MYSTATUSON},
-        {"mystatusoff", MSC_MYSTATUSOFF},
-        {"friendstatuson", MSC_FRIENDSTATUSON},
-        {"friendstatusoff", MSC_FRIENDSTATUSOFF},
         {"notintown", MSC_NOTINTOWN},
-        {"attackpcgt", MSC_ATTACKPCGT},
-        {"attackpcge", MSC_ATTACKPCGE},
         {"slavelt", MSC_SLAVELT},
         {"slavele", MSC_SLAVELE},
-        {"closedattacked", MSC_CLOSEDATTACKED},
-        {"longrangeattacked", MSC_LONGRANGEATTACKED},
-        {"skillused", MSC_SKILLUSED},
-        {"casttargeted", MSC_CASTTARGETED},
-    };
-    const struct
-    {
-        char str[32];
-        StatusChange id;
-    } cond2[] =
-    {
-        {"anybad", StatusChange::ANY_BAD},
-        {"stone", SC_STONE},
-        {"freeze", SC_FREEZE},
-        {"stan", SC_STAN},
-        {"sleep", SC_SLEEP},
-        {"poison", SC_POISON},
-        {"curse", SC_CURSE},
-        {"silence", SC_SILENCE},
-        {"confusion", SC_CONFUSION},
-        {"blind", SC_BLIND},
-        {"hiding", SC_HIDING},
-        {"sight", SC_SIGHT},
     };
     const struct
     {
         char str[32];
-        MSS id;
+        MobSkillState id;
     } state[] =
     {
-        {"any", MSS::ANY},
+        {"any", MobSkillState::ANY},
         {"idle", MSS_IDLE},
         {"walk", MSS_WALK},
         {"attack", MSS_ATTACK},
-        {"dead", MSS_DEAD},
-        {"loot", MSS_LOOT},
-        {"chase", MSS_CHASE},
     };
     const struct
     {
         char str[32];
-        MST id;
+        MobSkillTarget id;
     } target[] =
     {
         {"target", MST_TARGET},
         {"self", MST_SELF},
-        {"friend", MST_FRIEND},
-        {"master", MST_MASTER},
-        {"around5", MST_AROUND5},
-        {"around6", MST_AROUND6},
-        {"around7", MST_AROUND7},
-        {"around8", MST_AROUND8},
-        {"around1", MST_AROUND1},
-        {"around2", MST_AROUND2},
-        {"around3", MST_AROUND3},
-        {"around4", MST_AROUND4},
-        {"around", MST_AROUND},
     };
 
     int x;
@@ -4322,7 +4012,7 @@ int mob_readskilldb(void)
                 continue;
             }
 
-            ms->state = MSS(atoi(sp[2]));
+            ms->state = static_cast<MobSkillState>(atoi(sp[2]));
             for (j = 0; j < sizeof(state) / sizeof(state[0]); j++)
             {
                 if (strcmp(sp[2], state[j].str) == 0)
@@ -4337,26 +4027,19 @@ int mob_readskilldb(void)
             ms->cancel = atoi(sp[8]);
             if (strcmp(sp[8], "yes") == 0)
                 ms->cancel = 1;
-            ms->target = MST(atoi(sp[9]));
+            ms->target = static_cast<MobSkillTarget>(atoi(sp[9]));
             for (j = 0; j < sizeof(target) / sizeof(target[0]); j++)
             {
                 if (strcmp(sp[9], target[j].str) == 0)
                     ms->target = target[j].id;
             }
-            ms->cond1 = MSC::ANY;
+            ms->cond1 = MobSkillCondition::ANY;
             for (j = 0; j < sizeof(cond1) / sizeof(cond1[0]); j++)
             {
                 if (strcmp(sp[10], cond1[j].str) == 0)
                     ms->cond1 = cond1[j].id;
             }
-            // sometimes legitimately an integer
-            // in fact, with current data it always is. Yay!
             ms->cond2i = atoi(sp[11]);
-            for (j = 0; j < sizeof(cond2) / sizeof(cond2[0]); j++)
-            {
-                if (strcmp(sp[11], cond2[j].str) == 0)
-                    ms->cond2i = int(cond2[j].id);
-            }
             ms->val[0] = atoi(sp[12]);
             ms->val[1] = atoi(sp[13]);
             ms->val[2] = atoi(sp[14]);
diff --git a/src/map/mob.hpp b/src/map/mob.hpp
index 8247102..2d51eb0 100644
--- a/src/map/mob.hpp
+++ b/src/map/mob.hpp
@@ -13,17 +13,16 @@
 
 struct mob_skill
 {
-    MSS state;
+    MobSkillState state;
     SkillID skill_id;
     short skill_lv;
     short permillage;
     int casttime, delay;
     short cancel;
-    MSC cond1;
+    MobSkillCondition cond1;
     int cond2i;
-    StatusChange cond2sc() { return StatusChange(cond2i); }
     SkillID cond2sk() { return SkillID(cond2i); }
-    MST target;
+    MobSkillTarget target;
     int val[5];
     short emotion;
 };
@@ -38,7 +37,10 @@ struct mob_db
     int def, mdef;
     earray<int, ATTR, ATTR::COUNT> attrs;
     int range, range2, range3;
-    int size, race, element;
+    // always 1
+    int size;
+    Race race;
+    LevelElement element;
     MobMode mode;
     int speed, adelay, amotion, dmotion;
     int mexp, mexpper;
@@ -106,7 +108,7 @@ int mob_class_change(struct mob_data *md, int *value);
 int mob_warp(struct mob_data *md, int m, int x, int y, int type);
 
 int mobskill_use(struct mob_data *md, unsigned int tick,
-        MSC event, SkillID skill=SkillID::ZERO);
+        MobSkillCondition event, SkillID skill=SkillID::ZERO);
 int mobskill_event(struct mob_data *md, BF flag);
 void mobskill_castend_id(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data);
 void mobskill_castend_pos(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data);
diff --git a/src/map/mob.t.hpp b/src/map/mob.t.hpp
index 3c20e07..0fcd7f5 100644
--- a/src/map/mob.t.hpp
+++ b/src/map/mob.t.hpp
@@ -3,93 +3,52 @@
 
 #include <cstdint>
 
-enum class MST
+enum class MobSkillTarget
 {
     MST_TARGET = 0,
-#define MST_TARGET MST::MST_TARGET
+#define MST_TARGET MobSkillTarget::MST_TARGET
     MST_SELF,
-#define MST_SELF MST::MST_SELF
-    MST_FRIEND,
-#define MST_FRIEND MST::MST_FRIEND
-    MST_MASTER,
-#define MST_MASTER MST::MST_MASTER
-    MST_AROUND5,
-#define MST_AROUND5 MST::MST_AROUND5
-    MST_AROUND6,
-#define MST_AROUND6 MST::MST_AROUND6
-    MST_AROUND7,
-#define MST_AROUND7 MST::MST_AROUND7
-    MST_AROUND8,
-#define MST_AROUND8 MST::MST_AROUND8
-    MST_AROUND1,
-#define MST_AROUND1 MST::MST_AROUND1
-    MST_AROUND2,
-#define MST_AROUND2 MST::MST_AROUND2
-    MST_AROUND3,
-#define MST_AROUND3 MST::MST_AROUND3
-    MST_AROUND4,
-#define MST_AROUND4 MST::MST_AROUND4
-    MST_AROUND = MST_AROUND4,
-#define MST_AROUND MST::MST_AROUND
+#define MST_SELF MobSkillTarget::MST_SELF
 };
 
-enum class MSC : uint16_t
+/// Used as a condition when trying to apply the chosen mob skill.
+enum class MobSkillCondition : uint16_t
 {
     // used as something that never compares true
     NEVER_EQUAL = 0xfffe,
     ANY = 0xffff,
 
     MSC_ALWAYS = 0x0000,
-#define MSC_ALWAYS MSC::MSC_ALWAYS
+#define MSC_ALWAYS MobSkillCondition::MSC_ALWAYS
     MSC_MYHPLTMAXRATE = 0x0001,
-#define MSC_MYHPLTMAXRATE MSC::MSC_MYHPLTMAXRATE
-    MSC_FRIENDHPLTMAXRATE = 0x0010,
-#define MSC_FRIENDHPLTMAXRATE MSC::MSC_FRIENDHPLTMAXRATE
-    MSC_MYSTATUSON = 0x0020,
-#define MSC_MYSTATUSON MSC::MSC_MYSTATUSON
-    MSC_MYSTATUSOFF = 0x0021,
-#define MSC_MYSTATUSOFF MSC::MSC_MYSTATUSOFF
-    MSC_FRIENDSTATUSON = 0x0030,
-#define MSC_FRIENDSTATUSON MSC::MSC_FRIENDSTATUSON
-    MSC_FRIENDSTATUSOFF = 0x0031,
-#define MSC_FRIENDSTATUSOFF MSC::MSC_FRIENDSTATUSOFF
+#define MSC_MYHPLTMAXRATE MobSkillCondition::MSC_MYHPLTMAXRATE
+
     MSC_NOTINTOWN = 0x0032,
-#define MSC_NOTINTOWN MSC::MSC_NOTINTOWN
+#define MSC_NOTINTOWN MobSkillCondition::MSC_NOTINTOWN
 
-    MSC_ATTACKPCGT = 0x0100,
-#define MSC_ATTACKPCGT MSC::MSC_ATTACKPCGT
-    MSC_ATTACKPCGE = 0x0101,
-#define MSC_ATTACKPCGE MSC::MSC_ATTACKPCGE
     MSC_SLAVELT = 0x0110,
-#define MSC_SLAVELT MSC::MSC_SLAVELT
+#define MSC_SLAVELT MobSkillCondition::MSC_SLAVELT
     MSC_SLAVELE = 0x0111,
-#define MSC_SLAVELE MSC::MSC_SLAVELE
-    MSC_CLOSEDATTACKED = 0x1000,
-#define MSC_CLOSEDATTACKED MSC::MSC_CLOSEDATTACKED
-    MSC_LONGRANGEATTACKED = 0x1001,
-#define MSC_LONGRANGEATTACKED MSC::MSC_LONGRANGEATTACKED
-    MSC_SKILLUSED = 0x1010,
-#define MSC_SKILLUSED MSC::MSC_SKILLUSED
-    MSC_CASTTARGETED = 0x1011,
-#define MSC_CASTTARGETED MSC::MSC_CASTTARGETED
+#define MSC_SLAVELE MobSkillCondition::MSC_SLAVELE
 };
 
-enum class MSS : uint8_t
+/// Used as a filter when trying to choose a mob skill to use.
+enum class MobSkillState : uint8_t
 {
     ANY = 0xff,
 
     MSS_IDLE = 0,
-#define MSS_IDLE MSS::MSS_IDLE
+#define MSS_IDLE MobSkillState::MSS_IDLE
     MSS_WALK,
-#define MSS_WALK MSS::MSS_WALK
+#define MSS_WALK MobSkillState::MSS_WALK
     MSS_ATTACK,
-#define MSS_ATTACK MSS::MSS_ATTACK
+#define MSS_ATTACK MobSkillState::MSS_ATTACK
     MSS_DEAD,
-#define MSS_DEAD MSS::MSS_DEAD
+#define MSS_DEAD MobSkillState::MSS_DEAD
     MSS_LOOT,
-#define MSS_LOOT MSS::MSS_LOOT
+#define MSS_LOOT MobSkillState::MSS_LOOT
     MSS_CHASE,
-#define MSS_CHASE MSS::MSS_CHASE
+#define MSS_CHASE MobSkillState::MSS_CHASE
 };
 
 #endif // MOB_T_HPP
diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index c6cab1d..8501dc7 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -81,35 +81,23 @@ void npc_enable_sub(struct block_list *bl, struct npc_data *nd)
     free(name);
 }
 
-int npc_enable(const char *name, int flag)
+int npc_enable(const char *name, bool flag)
 {
     struct npc_data *nd = (struct npc_data *)strdb_search(npcname_db, name);
     if (nd == NULL)
         return 0;
 
-    if (flag & 1)
+    if (flag)
     {                           // 有効化
         nd->flag &= ~1;
         clif_spawnnpc(nd);
     }
-    else if (flag & 2)
-    {
-        nd->flag &= ~1;
-        nd->option = Option::ZERO;
-        clif_changeoption(&nd->bl);
-    }
-    else if (flag & 4)
-    {
-        nd->flag |= 1;
-        nd->option = Option::HIDE2;
-        clif_changeoption(&nd->bl);
-    }
     else
     {                           // 無効化
         nd->flag |= 1;
         clif_clearchar(&nd->bl, 0);
     }
-    if (flag & 3 && (nd->u.scr.xs > 0 || nd->u.scr.ys > 0))
+    if (flag && (nd->u.scr.xs > 0 || nd->u.scr.ys > 0))
         map_foreachinarea(std::bind(npc_enable_sub, ph::_1, nd),
                 nd->bl.m, nd->bl.x - nd->u.scr.xs, nd->bl.y - nd->u.scr.ys,
                 nd->bl.x + nd->u.scr.xs, nd->bl.y + nd->u.scr.ys, BL_PC);
@@ -209,7 +197,8 @@ void npc_event_doall_sub(db_key_t key, db_val_t data,
     const char *p = key.s;
     struct event_data *ev;
 
-    nullpo_retv(ev = (struct event_data *) data);
+    ev = (struct event_data *) data;
+    nullpo_retv(ev);
 
     if ((p = strchr(p, ':')) && p && strcasecmp(name, p) == 0)
     {
@@ -237,7 +226,8 @@ void npc_event_do_sub(db_key_t key, db_val_t data,
     const char *p = key.s;
     struct event_data *ev;
 
-    nullpo_retv(ev = (struct event_data *) data);
+    ev = (struct event_data *) data;
+    nullpo_retv(ev);
 
     if (p && strcasecmp(name, p) == 0)
     {
@@ -1090,7 +1080,7 @@ int npc_parse_warp(const char *w1, const char *, const char *w3, const char *w4)
     nd->bl.m = m;
     nd->bl.x = x;
     nd->bl.y = y;
-    nd->dir = 0;
+    nd->dir = DIR_S;
     nd->flag = 0;
     memcpy(nd->name, w3, 24);
     memcpy(nd->exname, w3, 24);
@@ -1144,18 +1134,23 @@ static
 int npc_parse_shop(char *w1, char *, char *w3, char *w4)
 {
     char *p;
-    int x, y, dir, m;
+    int x, y;
+    DIR dir;
+    int m;
     int max = 100, pos = 0;
     char mapname[24];
     struct npc_data *nd;
 
     // 引数の個数チェック
-    if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ||
-        strchr(w4, ',') == NULL)
+    int dir_; // TODO use SSCANF or extract
+    if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4
+        || dir_ < 0 || dir_ >= 8
+        || strchr(w4, ',') == NULL)
     {
         PRINTF("bad shop line : %s\n", w3);
         return 1;
     }
+    dir = static_cast<DIR>(dir_);
     m = map_mapname2mapid(mapname);
 
     nd = (struct npc_data *) calloc(1, sizeof(struct npc_data) +
@@ -1282,7 +1277,9 @@ static
 int npc_parse_script(char *w1, char *w2, char *w3, char *w4,
                       const char *first_line, FILE * fp, int *lines)
 {
-    int x, y, dir = 0, m, xs = 0, ys = 0, npc_class = 0;   // [Valaris] thanks to fov
+    int x, y;
+    DIR dir = DIR_S;
+    int m, xs = 0, ys = 0, npc_class = 0;   // [Valaris] thanks to fov
     char mapname[24];
     char *srcbuf = NULL;
     const ScriptCode *script = NULL;
@@ -1306,12 +1303,15 @@ int npc_parse_script(char *w1, char *w2, char *w3, char *w4,
     else
     {
         // 引数の個数チェック
-        if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ||
-            (strcmp(w2, "script") == 0 && strchr(w4, ',') == NULL))
+        int dir_; // TODO use SSCANF or extract
+        if (sscanf(w1, "%[^,],%d,%d,%d", mapname, &x, &y, &dir_) != 4
+            || dir_ < 0 || dir_ >= 8
+            || (strcmp(w2, "script") == 0 && strchr(w4, ',') == NULL))
         {
             PRINTF("bad script line : %s\n", w3);
             return 1;
         }
+        dir = static_cast<DIR>(dir_);
         m = map_mapname2mapid(mapname);
     }
 
diff --git a/src/map/npc.hpp b/src/map/npc.hpp
index 9af2721..09fb1dc 100644
--- a/src/map/npc.hpp
+++ b/src/map/npc.hpp
@@ -21,7 +21,7 @@ int npc_buylist(struct map_session_data *, int, const uint16_t *);
 int npc_selllist(struct map_session_data *, int, const uint16_t *);
 int npc_parse_warp(const char *w1, const char *w2, const char *w3, const char *w4);
 
-int npc_enable(const char *name, int flag);
+int npc_enable(const char *name, bool flag);
 struct npc_data *npc_name2id(const char *name);
 
 int npc_get_new_npc_id(void);
diff --git a/src/map/path.cpp b/src/map/path.cpp
index 3766999..b764e7f 100644
--- a/src/map/path.cpp
+++ b/src/map/path.cpp
@@ -12,7 +12,8 @@
 struct tmp_path
 {
     short x, y, dist, before, cost;
-    char dir, flag;
+    DIR dir;
+    char flag;
 };
 #define calc_index(x,y) (((x)+(y)*MAX_WALKPATH) & (MAX_WALKPATH*MAX_WALKPATH-1))
 
@@ -128,7 +129,7 @@ int calc_cost(struct tmp_path *p, int x1, int y1)
  */
 static
 int add_path(int *heap, struct tmp_path *tp, int x, int y, int dist,
-                     int dir, int before, int x1, int y1)
+        DIR dir, int before, int x1, int y1)
 {
     int i;
 
@@ -195,8 +196,7 @@ int can_place(struct map_data *m, int x, int y, int flag)
  *------------------------------------------
  */
 static
-int can_move(struct map_data *m, int x0, int y0, int x1, int y1,
-                     int flag)
+int can_move(struct map_data *m, int x0, int y0, int x1, int y1, int flag)
 {
     nullpo_ret(m);
 
@@ -270,8 +270,7 @@ int path_blownpos(int m, int x0, int y0, int dx, int dy, int count)
  * path探索 (x0,y0)->(x1,y1)
  *------------------------------------------
  */
-int path_search(struct walkpath_data *wpd, int m, int x0, int y0, int x1,
-                 int y1, int flag)
+int path_search(struct walkpath_data *wpd, int m, int x0, int y0, int x1, int y1, int flag)
 {
     int heap[MAX_HEAP + 1];
     struct tmp_path tp[MAX_WALKPATH * MAX_WALKPATH];
@@ -301,22 +300,23 @@ int path_search(struct walkpath_data *wpd, int m, int x0, int y0, int x1,
                 break;
             x += dx;
             y += dy;
-            wpd->path[i++] =
-                (dx < 0) ? ((dy > 0) ? 1 : 3) : ((dy < 0) ? 5 : 7);
+            wpd->path[i++] = (dx < 0)
+                ? ((dy > 0) ? DIR_SW : DIR_NW)
+                : ((dy < 0) ? DIR_NE : DIR_SE);
         }
         else if (x != x1)
         {
             if (!can_move(md, x, y, x + dx, y, flag))
                 break;
             x += dx;
-            wpd->path[i++] = (dx < 0) ? 2 : 6;
+            wpd->path[i++] = (dx < 0) ? DIR_W : DIR_E;
         }
         else
         {                       // y!=y1
             if (!can_move(md, x, y, x, y + dy, flag))
                 break;
             y += dy;
-            wpd->path[i++] = (dy > 0) ? 0 : 4;
+            wpd->path[i++] = (dy > 0) ? DIR_S : DIR_N;
         }
         if (x == x1 && y == y1)
         {
@@ -335,7 +335,7 @@ int path_search(struct walkpath_data *wpd, int m, int x0, int y0, int x1,
     tp[i].x = x0;
     tp[i].y = y0;
     tp[i].dist = 0;
-    tp[i].dir = 0;
+    tp[i].dir = DIR_S;
     tp[i].before = 0;
     tp[i].cost = calc_cost(&tp[i], x1, y1);
     tp[i].flag = 0;
@@ -367,29 +367,21 @@ int path_search(struct walkpath_data *wpd, int m, int x0, int y0, int x1,
             return 0;
         }
         if (can_move(md, x, y, x + 1, y - 1, flag))
-            e += add_path(heap, tp, x + 1, y - 1, tp[rp].dist + 14, 5, rp,
-                           x1, y1);
+            e += add_path(heap, tp, x + 1, y - 1, tp[rp].dist + 14, DIR_NE, rp, x1, y1);
         if (can_move(md, x, y, x + 1, y, flag))
-            e += add_path(heap, tp, x + 1, y, tp[rp].dist + 10, 6, rp, x1,
-                           y1);
+            e += add_path(heap, tp, x + 1, y, tp[rp].dist + 10, DIR_E, rp, x1, y1);
         if (can_move(md, x, y, x + 1, y + 1, flag))
-            e += add_path(heap, tp, x + 1, y + 1, tp[rp].dist + 14, 7, rp,
-                           x1, y1);
+            e += add_path(heap, tp, x + 1, y + 1, tp[rp].dist + 14, DIR_SE, rp, x1, y1);
         if (can_move(md, x, y, x, y + 1, flag))
-            e += add_path(heap, tp, x, y + 1, tp[rp].dist + 10, 0, rp, x1,
-                           y1);
+            e += add_path(heap, tp, x, y + 1, tp[rp].dist + 10, DIR_S, rp, x1, y1);
         if (can_move(md, x, y, x - 1, y + 1, flag))
-            e += add_path(heap, tp, x - 1, y + 1, tp[rp].dist + 14, 1, rp,
-                           x1, y1);
+            e += add_path(heap, tp, x - 1, y + 1, tp[rp].dist + 14, DIR_SW, rp, x1, y1);
         if (can_move(md, x, y, x - 1, y, flag))
-            e += add_path(heap, tp, x - 1, y, tp[rp].dist + 10, 2, rp, x1,
-                           y1);
+            e += add_path(heap, tp, x - 1, y, tp[rp].dist + 10, DIR_W, rp, x1, y1);
         if (can_move(md, x, y, x - 1, y - 1, flag))
-            e += add_path(heap, tp, x - 1, y - 1, tp[rp].dist + 14, 3, rp,
-                           x1, y1);
+            e += add_path(heap, tp, x - 1, y - 1, tp[rp].dist + 14, DIR_NW, rp, x1, y1);
         if (can_move(md, x, y, x, y - 1, flag))
-            e += add_path(heap, tp, x, y - 1, tp[rp].dist + 10, 4, rp, x1,
-                           y1);
+            e += add_path(heap, tp, x, y - 1, tp[rp].dist + 10, DIR_N, rp, x1, y1);
         tp[rp].flag = 1;
         if (e || heap[0] >= MAX_HEAP - 5)
             return -1;
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index dc7c77c..9826323 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -191,11 +191,6 @@ static int stat_p[MAX_LEVEL] =
     8670,8736,8802,8868,8935,   9002,
 };
 
-static
-int dirx[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
-static
-int diry[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
-
 static
 earray<EPOS, EQUIP, EQUIP::COUNT> equip_pos //=
 {{
@@ -431,14 +426,6 @@ int pc_setrestartvalue(struct map_session_data *sd, int type)
 {
     nullpo_ret(sd);
 
-    //-----------------------
-    // 死亡した
-    if (sd->special_state.restart_full_recover)
-    {                           // オシリスカード
-        sd->status.hp = sd->status.max_hp;
-        sd->status.sp = sd->status.max_sp;
-    }
-    else
     {
         if (battle_config.restart_hp_rate < 50)
             sd->status.hp = (sd->status.max_hp) / 2;
@@ -728,7 +715,7 @@ int pc_breakweapon(struct map_session_data *sd)
 
     if (sd == NULL)
         return -1;
-    if (sd->unbreakable >= MRAND(100))
+    if (!MRAND(100))
         return 0;
 
     for (i = 0; i < MAX_INVENTORY; i++)
@@ -767,7 +754,7 @@ int pc_breakarmor(struct map_session_data *sd)
 {
     if (sd == NULL)
         return -1;
-    if (sd->unbreakable >= MRAND(100))
+    if (!MRAND(100))
         return 0;
 
     for (int i = 0; i < MAX_INVENTORY; i++)
@@ -839,15 +826,12 @@ int pc_authok(int id, int login_id2, time_t connect_until_time,
     sd->weapontype1 = sd->weapontype2 = 0;
     sd->speed = DEFAULT_WALK_SPEED;
     sd->state.dead_sit = 0;
-    sd->dir = 0;
-    sd->head_dir = 0;
+    sd->dir = DIR_S;
+    sd->head_dir = DIR_S;
     sd->state.auth = 1;
     sd->walktimer = -1;
     sd->attacktimer = -1;
     sd->followtimer = -1;       // [MouseJstr]
-    sd->skilltimer = -1;
-    sd->skillitem = SkillID::NEGATIVE;
-    sd->skillitemlv = -1;
     sd->invincible_timer = -1;
     sd->sg_count = 0;
 
@@ -877,8 +861,6 @@ int pc_authok(int id, int login_id2, time_t connect_until_time,
     sd->spiritball = 0;
     for (int i = 0; i < MAX_SKILL_LEVEL; i++)
         sd->spirit_timer[i] = -1;
-    for (int i = 0; i < MAX_SKILLTIMERSKILL; i++)
-        sd->skilltimerskill[i].timer = -1;
 
     memset(&sd->dev, 0, sizeof(struct square));
     for (int i = 0; i < 5; i++)
@@ -904,13 +886,9 @@ int pc_authok(int id, int login_id2, time_t connect_until_time,
     sd->sc_count = 0;
     if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
         (pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide)))
-        sd->status.option &= (Option::MASK | Option::HIDE);
+        sd->status.option &= Option::HIDE;
     else
-        sd->status.option &= Option::MASK;
-
-    // スキルユニット関係の初期化
-    memset(sd->skillunit, 0, sizeof(sd->skillunit));
-    memset(sd->skillunittick, 0, sizeof(sd->skillunittick));
+        sd->status.option = Option::ZERO;
 
     // init ignore list
     memset(sd->ignore, 0, sizeof(sd->ignore));
@@ -1135,7 +1113,7 @@ int pc_calcstatus(struct map_session_data *sd, int first)
     int b_base_atk;
     earray<struct skill, SkillID, MAX_SKILL> b_skill;
     int bl, index;
-    int aspd_rate, wele, wele_, def_ele, refinedef = 0;
+    int aspd_rate, refinedef = 0;
     int str, dstr, dex;
 
     nullpo_ret(sd);
@@ -1217,8 +1195,6 @@ int pc_calcstatus(struct map_session_data *sd, int first)
     sd->status.max_sp = 0;
     sd->attackrange = 0;
     sd->attackrange_ = 0;
-    sd->atk_ele = 0;
-    sd->def_ele = 0;
     sd->star = 0;
     sd->overrefine = 0;
     sd->matk1 = 0;
@@ -1226,26 +1202,17 @@ int pc_calcstatus(struct map_session_data *sd, int first)
     sd->speed = DEFAULT_WALK_SPEED;
     sd->hprate = 100;
     sd->sprate = 100;
-    sd->castrate = 100;
     sd->dsprate = 100;
     sd->base_atk = 0;
     sd->arrow_atk = 0;
-    sd->arrow_ele = 0;
     sd->arrow_hit = 0;
     sd->arrow_range = 0;
     sd->nhealhp = sd->nhealsp = sd->nshealhp = sd->nshealsp = sd->nsshealhp =
         sd->nsshealsp = 0;
-    for (int& ire : sd->addeff)
-        ire = 0;
-    for (int& ire : sd->addeff2)
-        ire = 0;
-    for (int& ire : sd->reseff)
-        ire = 0;
     memset(&sd->special_state, 0, sizeof(sd->special_state));
 
     sd->watk_ = 0;              //二刀流用(仮)
     sd->watk_2 = 0;
-    sd->atk_ele_ = 0;
     sd->star_ = 0;
     sd->overrefine_ = 0;
 
@@ -1255,38 +1222,17 @@ int pc_calcstatus(struct map_session_data *sd, int first)
     sd->sprecov_rate = 100;
     sd->critical_def = 0;
     sd->double_rate = 0;
-    sd->near_attack_def_rate = sd->long_attack_def_rate = 0;
     sd->atk_rate = sd->matk_rate = 100;
-    sd->ignore_def_ele = sd->ignore_def_race = 0;
-    sd->ignore_def_ele_ = sd->ignore_def_race_ = 0;
-    sd->ignore_mdef_ele = sd->ignore_mdef_race = 0;
     sd->arrow_cri = 0;
-    sd->magic_def_rate = sd->misc_def_rate = 0;
-    for (int& ire : sd->arrow_addeff)
-        ire = 0;
-    for (int& ire : sd->arrow_addeff2)
-        ire = 0;
     sd->perfect_hit = 0;
     sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
     sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
-    sd->def_ratio_atk_ele = sd->def_ratio_atk_ele_ = 0;
-    sd->def_ratio_atk_race = sd->def_ratio_atk_race_ = 0;
-    sd->get_zeny_num = 0;
-    sd->monster_drop_item_count = 0;
-    memset(sd->monster_drop_race, 0, sizeof(sd->monster_drop_race));
-    memset(sd->monster_drop_itemrate, 0, sizeof(sd->monster_drop_itemrate));
     sd->speed_add_rate = sd->aspd_add_rate = 100;
-    sd->double_add_rate = sd->perfect_hit_add = sd->get_zeny_add_num = 0;
-    sd->splash_range = sd->splash_add_range = 0;
-    sd->autospell_id = SkillID::ZERO;
-    sd->autospell_lv = sd->autospell_rate = 0;
+    sd->double_add_rate = sd->perfect_hit_add = 0;
     sd->hp_drain_rate = sd->hp_drain_per = sd->sp_drain_rate =
         sd->sp_drain_per = 0;
     sd->hp_drain_rate_ = sd->hp_drain_per_ = sd->sp_drain_rate_ =
         sd->sp_drain_per_ = 0;
-    sd->short_weapon_damage_return = sd->long_weapon_damage_return = 0;
-    sd->magic_damage_return = 0;    //AppleGirl Was Here
-    sd->random_attack_increase_add = sd->random_attack_increase_per = 0;
 
     sd->spellpower_bonus_target = 0;
 
@@ -1371,9 +1317,6 @@ int pc_calcstatus(struct map_session_data *sd, int first)
     if (sd->spellpower_bonus_target < sd->spellpower_bonus_current)
         sd->spellpower_bonus_current = sd->spellpower_bonus_target;
 
-    wele = sd->atk_ele;
-    wele_ = sd->atk_ele_;
-    def_ele = sd->def_ele;
     sd->paramcard = sd->parame;
 
     // 装備品によるステータス変化はここで実行
@@ -1409,7 +1352,6 @@ int pc_calcstatus(struct map_session_data *sd, int first)
                     if (sd->status.inventory[index].card[0] == 0x00ff)
                     {           // 製造武器
                         sd->star_ = (sd->status.inventory[index].card[1] >> 8); // 星のかけら
-                        wele_ = (sd->status.inventory[index].card[1] & 0x0f);   // 属 性
                     }
                     sd->attackrange_ += sd->inventory_data[index]->range;
                     sd->state.lr_flag = 1;
@@ -1440,7 +1382,6 @@ int pc_calcstatus(struct map_session_data *sd, int first)
                     if (sd->status.inventory[index].card[0] == 0x00ff)
                     {           // 製造武器
                         sd->star += (sd->status.inventory[index].card[1] >> 8); // 星のかけら
-                        wele = (sd->status.inventory[index].card[1] & 0x0f);    // 属 性
                     }
                     sd->attackrange += sd->inventory_data[index]->range;
                     run_script_l(sd->inventory_data[index]->equip_script, 0,
@@ -1498,16 +1439,8 @@ int pc_calcstatus(struct map_session_data *sd, int first)
         sd->attackrange = sd->attackrange_;
     if (sd->status.weapon == 11)
         sd->attackrange += sd->arrow_range;
-    if (wele > 0)
-        sd->atk_ele = wele;
-    if (wele_ > 0)
-        sd->atk_ele_ = wele_;
-    if (def_ele > 0)
-        sd->def_ele = def_ele;
     sd->double_rate += sd->double_add_rate;
     sd->perfect_hit += sd->perfect_hit_add;
-    sd->get_zeny_num += sd->get_zeny_add_num;
-    sd->splash_range += sd->splash_add_range;
     if (sd->speed_add_rate != 100)
         sd->speed_rate += sd->speed_add_rate - 100;
     if (sd->aspd_add_rate != 100)
@@ -1821,7 +1754,6 @@ int pc_calcstatus(struct map_session_data *sd, int first)
  * 装 備品による能力等のボーナス設定
  *------------------------------------------
  */
-// TODO: in each pc_bonus*, purge all 'type' not used by scripts
 int pc_bonus(struct map_session_data *sd, SP type, int val)
 {
     nullpo_ret(sd);
@@ -1837,49 +1769,56 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
             if (sd->state.lr_flag != 2)
                 sd->parame[sp_to_attr(type)] += val;
             break;
+#if 0
         case SP_ATK1:
             if (!sd->state.lr_flag)
                 sd->watk += val;
             else if (sd->state.lr_flag == 1)
                 sd->watk_ += val;
             break;
+#endif
+#if 0
         case SP_ATK2:
             if (!sd->state.lr_flag)
                 sd->watk2 += val;
             else if (sd->state.lr_flag == 1)
                 sd->watk_2 += val;
             break;
+#endif
+#if 0
         case SP_BASE_ATK:
             if (sd->state.lr_flag != 2)
                 sd->base_atk += val;
             break;
+#endif
+#if 0
         case SP_MATK1:
             if (sd->state.lr_flag != 2)
                 sd->matk1 += val;
             break;
+#endif
+#if 0
         case SP_MATK2:
             if (sd->state.lr_flag != 2)
                 sd->matk2 += val;
             break;
-        case SP_MATK:
-            if (sd->state.lr_flag != 2)
-            {
-                sd->matk1 += val;
-                sd->matk2 += val;
-            }
-            break;
+#endif
+#if 0
         case SP_DEF1:
             if (sd->state.lr_flag != 2)
                 sd->def += val;
             break;
+#endif
         case SP_MDEF1:
             if (sd->state.lr_flag != 2)
                 sd->mdef += val;
             break;
+#if 0
         case SP_MDEF2:
             if (sd->state.lr_flag != 2)
                 sd->mdef += val;
             break;
+#endif
         case SP_HIT:
             if (sd->state.lr_flag != 2)
                 sd->hit += val;
@@ -1890,28 +1829,18 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
             if (sd->state.lr_flag != 2)
                 sd->flee += val;
             break;
+#if 0
         case SP_FLEE2:
             if (sd->state.lr_flag != 2)
                 sd->flee2 += val * 10;
             break;
+#endif
         case SP_CRITICAL:
             if (sd->state.lr_flag != 2)
                 sd->critical += val * 10;
             else
                 sd->arrow_cri += val * 10;
             break;
-        case SP_ATKELE:
-            if (!sd->state.lr_flag)
-                sd->atk_ele = val;
-            else if (sd->state.lr_flag == 1)
-                sd->atk_ele_ = val;
-            else if (sd->state.lr_flag == 2)
-                sd->arrow_ele = val;
-            break;
-        case SP_DEFELE:
-            if (sd->state.lr_flag != 2)
-                sd->def_ele = val;
-            break;
         case SP_MAXHP:
             if (sd->state.lr_flag != 2)
                 sd->status.max_hp += val;
@@ -1920,22 +1849,22 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
             if (sd->state.lr_flag != 2)
                 sd->status.max_sp += val;
             break;
-        case SP_CASTRATE:
-            if (sd->state.lr_flag != 2)
-                sd->castrate += val;
-            break;
         case SP_MAXHPRATE:
             if (sd->state.lr_flag != 2)
                 sd->hprate += val;
             break;
+#if 0
         case SP_MAXSPRATE:
             if (sd->state.lr_flag != 2)
                 sd->sprate += val;
             break;
+#endif
+#if 0
         case SP_SPRATE:
             if (sd->state.lr_flag != 2)
                 sd->dsprate += val;
             break;
+#endif
         case SP_ATTACKRANGE:
             if (!sd->state.lr_flag)
                 sd->attackrange += val;
@@ -1944,10 +1873,13 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
             else if (sd->state.lr_flag == 2)
                 sd->arrow_range += val;
             break;
+#if 0
         case SP_ADD_SPEED:
             if (sd->state.lr_flag != 2)
                 sd->speed -= val;
             break;
+#endif
+#if 0
         case SP_SPEED_RATE:
             if (sd->state.lr_flag != 2)
             {
@@ -1955,14 +1887,17 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
                     sd->speed_rate = 100 - val;
             }
             break;
+#endif
         case SP_SPEED_ADDRATE:
             if (sd->state.lr_flag != 2)
                 sd->speed_add_rate = sd->speed_add_rate * (100 - val) / 100;
             break;
+#if 0
         case SP_ASPD:
             if (sd->state.lr_flag != 2)
                 sd->aspd -= val * 10;
             break;
+#endif
         case SP_ASPD_RATE:
             if (sd->state.lr_flag != 2)
             {
@@ -1970,118 +1905,86 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
                     sd->aspd_rate = 100 - val;
             }
             break;
+#if 0
         case SP_ASPD_ADDRATE:
             if (sd->state.lr_flag != 2)
                 sd->aspd_add_rate = sd->aspd_add_rate * (100 - val) / 100;
             break;
+#endif
         case SP_HP_RECOV_RATE:
             if (sd->state.lr_flag != 2)
                 sd->hprecov_rate += val;
             break;
+#if 0
         case SP_SP_RECOV_RATE:
             if (sd->state.lr_flag != 2)
                 sd->sprecov_rate += val;
             break;
+#endif
+#if 0
         case SP_CRITICAL_DEF:
             if (sd->state.lr_flag != 2)
                 sd->critical_def += val;
             break;
-        case SP_NEAR_ATK_DEF:
-            if (sd->state.lr_flag != 2)
-                sd->near_attack_def_rate += val;
-            break;
-        case SP_LONG_ATK_DEF:
-            if (sd->state.lr_flag != 2)
-                sd->long_attack_def_rate += val;
-            break;
+#endif
+#if 0
         case SP_DOUBLE_RATE:
             if (sd->state.lr_flag == 0 && sd->double_rate < val)
                 sd->double_rate = val;
             break;
+#endif
         case SP_DOUBLE_ADD_RATE:
             if (sd->state.lr_flag == 0)
                 sd->double_add_rate += val;
             break;
+#if 0
         case SP_MATK_RATE:
             if (sd->state.lr_flag != 2)
                 sd->matk_rate += val;
             break;
-        case SP_IGNORE_DEF_ELE:
-            if (!sd->state.lr_flag)
-                sd->ignore_def_ele |= 1 << val;
-            else if (sd->state.lr_flag == 1)
-                sd->ignore_def_ele_ |= 1 << val;
-            break;
-        case SP_IGNORE_DEF_RACE:
-            if (!sd->state.lr_flag)
-                sd->ignore_def_race |= 1 << val;
-            else if (sd->state.lr_flag == 1)
-                sd->ignore_def_race_ |= 1 << val;
-            break;
+#endif
+#if 0
         case SP_ATK_RATE:
             if (sd->state.lr_flag != 2)
                 sd->atk_rate += val;
             break;
-        case SP_MAGIC_ATK_DEF:
-            if (sd->state.lr_flag != 2)
-                sd->magic_def_rate += val;
-            break;
-        case SP_MISC_ATK_DEF:
-            if (sd->state.lr_flag != 2)
-                sd->misc_def_rate += val;
-            break;
-        case SP_IGNORE_MDEF_ELE:
-            if (sd->state.lr_flag != 2)
-                sd->ignore_mdef_ele |= 1 << val;
-            break;
-        case SP_IGNORE_MDEF_RACE:
-            if (sd->state.lr_flag != 2)
-                sd->ignore_mdef_race |= 1 << val;
-            break;
+#endif
+#if 0
         case SP_PERFECT_HIT_RATE:
             if (sd->state.lr_flag != 2 && sd->perfect_hit < val)
                 sd->perfect_hit = val;
             break;
+#endif
+#if 0
         case SP_PERFECT_HIT_ADD_RATE:
             if (sd->state.lr_flag != 2)
                 sd->perfect_hit_add += val;
             break;
+#endif
+#if 0
         case SP_CRITICAL_RATE:
             if (sd->state.lr_flag != 2)
                 sd->critical_rate += val;
             break;
-        case SP_GET_ZENY_NUM:
-            if (sd->state.lr_flag != 2 && sd->get_zeny_num < val)
-                sd->get_zeny_num = val;
-            break;
-        case SP_ADD_GET_ZENY_NUM:
-            if (sd->state.lr_flag != 2)
-                sd->get_zeny_add_num += val;
-            break;
-        case SP_DEF_RATIO_ATK_ELE:
-            if (!sd->state.lr_flag)
-                sd->def_ratio_atk_ele |= 1 << val;
-            else if (sd->state.lr_flag == 1)
-                sd->def_ratio_atk_ele_ |= 1 << val;
-            break;
-        case SP_DEF_RATIO_ATK_RACE:
-            if (!sd->state.lr_flag)
-                sd->def_ratio_atk_race |= 1 << val;
-            else if (sd->state.lr_flag == 1)
-                sd->def_ratio_atk_race_ |= 1 << val;
-            break;
+#endif
+#if 0
         case SP_HIT_RATE:
             if (sd->state.lr_flag != 2)
                 sd->hit_rate += val;
             break;
+#endif
+#if 0
         case SP_FLEE_RATE:
             if (sd->state.lr_flag != 2)
                 sd->flee_rate += val;
             break;
+#endif
+#if 0
         case SP_FLEE2_RATE:
             if (sd->state.lr_flag != 2)
                 sd->flee2_rate += val;
             break;
+#endif
         case SP_DEF_RATE:
             if (sd->state.lr_flag != 2)
                 sd->def_rate += val;
@@ -2090,107 +1993,18 @@ int pc_bonus(struct map_session_data *sd, SP type, int val)
             if (sd->state.lr_flag != 2)
                 sd->def2_rate += val;
             break;
+#if 0
         case SP_MDEF_RATE:
             if (sd->state.lr_flag != 2)
                 sd->mdef_rate += val;
             break;
+#endif
+#if 0
         case SP_MDEF2_RATE:
             if (sd->state.lr_flag != 2)
                 sd->mdef2_rate += val;
             break;
-        case SP_RESTART_FULL_RECORVER:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.restart_full_recover = 1;
-            break;
-        case SP_NO_CASTCANCEL:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_castcancel = 1;
-            break;
-        case SP_NO_CASTCANCEL2:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_castcancel2 = 1;
-            break;
-        case SP_NO_SIZEFIX:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_sizefix = 1;
-            break;
-        case SP_NO_MAGIC_DAMAGE:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_magic_damage = 1;
-            break;
-        case SP_NO_WEAPON_DAMAGE:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_weapon_damage = 1;
-            break;
-        case SP_NO_GEMSTONE:
-            if (sd->state.lr_flag != 2)
-                sd->special_state.no_gemstone = 1;
-            break;
-        case SP_SPLASH_RANGE:
-            if (sd->state.lr_flag != 2 && sd->splash_range < val)
-                sd->splash_range = val;
-            break;
-        case SP_SPLASH_ADD_RANGE:
-            if (sd->state.lr_flag != 2)
-                sd->splash_add_range += val;
-            break;
-        case SP_SHORT_WEAPON_DAMAGE_RETURN:
-            if (sd->state.lr_flag != 2)
-                sd->short_weapon_damage_return += val;
-            break;
-        case SP_LONG_WEAPON_DAMAGE_RETURN:
-            if (sd->state.lr_flag != 2)
-                sd->long_weapon_damage_return += val;
-            break;
-        case SP_MAGIC_DAMAGE_RETURN:   //AppleGirl Was Here
-            if (sd->state.lr_flag != 2)
-                sd->magic_damage_return += val;
-            break;
-        case SP_ALL_STATS:     // [Valaris]
-            if (sd->state.lr_flag != 2)
-            {
-                for (ATTR attr : ATTRs)
-                    sd->parame[attr] += val;
-                clif_updatestatus(sd, SP_STR);
-                clif_updatestatus(sd, SP_AGI);
-                clif_updatestatus(sd, SP_VIT);
-                clif_updatestatus(sd, SP_INT);
-                clif_updatestatus(sd, SP_DEX);
-                clif_updatestatus(sd, SP_LUK);
-            }
-            break;
-        case SP_AGI_VIT:       // [Valaris]
-            if (sd->state.lr_flag != 2)
-            {
-                sd->parame[ATTR::AGI] += val;
-                sd->parame[ATTR::VIT] += val;
-                clif_updatestatus(sd, SP_AGI);
-                clif_updatestatus(sd, SP_VIT);
-            }
-            break;
-        case SP_AGI_DEX_STR:   // [Valaris]
-            if (sd->state.lr_flag != 2)
-            {
-                sd->parame[ATTR::AGI] += val;
-                sd->parame[ATTR::DEX] += val;
-                sd->parame[ATTR::STR] += val;
-                clif_updatestatus(sd, SP_AGI);
-                clif_updatestatus(sd, SP_DEX);
-                clif_updatestatus(sd, SP_STR);
-            }
-            break;
-        case SP_PERFECT_HIDE:  // [Valaris]
-            if (sd->state.lr_flag != 2)
-            {
-                sd->perfect_hiding = 1;
-            }
-            break;
-        case SP_UNBREAKABLE:
-            if (sd->state.lr_flag != 2)
-            {
-                sd->unbreakable += val;
-            }
-            break;
+#endif
         case SP_DEAF:
             sd->special_state.deaf = 1;
             break;
@@ -2213,22 +2027,6 @@ int pc_bonus2(struct map_session_data *sd, SP type, int type2, int val)
 
     switch (type)
     {
-        case SP_ADDEFF:
-            if (sd->state.lr_flag != 2)
-                sd->addeff[BadSC(type2)] += val;
-            else
-                sd->arrow_addeff[BadSC(type2)] += val;
-            break;
-        case SP_ADDEFF2:
-            if (sd->state.lr_flag != 2)
-                sd->addeff2[BadSC(type2)] += val;
-            else
-                sd->arrow_addeff2[BadSC(type2)] += val;
-            break;
-        case SP_RESEFF:
-            if (sd->state.lr_flag != 2)
-                sd->reseff[BadSC(type2)] += val;
-            break;
         case SP_HP_DRAIN_RATE:
             if (!sd->state.lr_flag)
             {
@@ -2241,6 +2039,7 @@ int pc_bonus2(struct map_session_data *sd, SP type, int type2, int val)
                 sd->hp_drain_per_ += val;
             }
             break;
+#if 0
         case SP_SP_DRAIN_RATE:
             if (!sd->state.lr_flag)
             {
@@ -2253,14 +2052,7 @@ int pc_bonus2(struct map_session_data *sd, SP type, int type2, int val)
                 sd->sp_drain_per_ += val;
             }
             break;
-        case SP_RANDOM_ATTACK_INCREASE:    // [Valaris]
-            if (sd->state.lr_flag != 2)
-            {
-                sd->random_attack_increase_add = type2;
-                sd->random_attack_increase_per += val;
-                break;
-            }                   // end addition
-            break;
+#endif
         default:
             if (battle_config.error_log)
                 PRINTF("pc_bonus2: unknown type %d %d %d!\n",
@@ -2270,56 +2062,6 @@ int pc_bonus2(struct map_session_data *sd, SP type, int type2, int val)
     return 0;
 }
 
-int pc_bonus3(struct map_session_data *sd, SP type, int type2, int type3,
-               int val)
-{
-    int i;
-    switch (type)
-    {
-        case SP_ADD_MONSTER_DROP_ITEM:
-            if (sd->state.lr_flag != 2)
-            {
-                for (i = 0; i < sd->monster_drop_item_count; i++)
-                {
-                    if (sd->monster_drop_itemid[i] == type2)
-                    {
-                        sd->monster_drop_race[i] |= 1 << type3;
-                        if (sd->monster_drop_itemrate[i] < val)
-                            sd->monster_drop_itemrate[i] = val;
-                        break;
-                    }
-                }
-                if (i >= sd->monster_drop_item_count
-                    && sd->monster_drop_item_count < 10)
-                {
-                    sd->monster_drop_itemid[sd->monster_drop_item_count] =
-                        type2;
-                    sd->monster_drop_race[sd->monster_drop_item_count] |=
-                        1 << type3;
-                    sd->monster_drop_itemrate[sd->monster_drop_item_count] =
-                        val;
-                    sd->monster_drop_item_count++;
-                }
-            }
-            break;
-        case SP_AUTOSPELL:
-            if (sd->state.lr_flag != 2)
-            {
-                sd->autospell_id = SkillID(type2);
-                sd->autospell_lv = type3;
-                sd->autospell_rate = val;
-            }
-            break;
-        default:
-            if (battle_config.error_log)
-                PRINTF("pc_bonus3: unknown type %d %d %d %d!\n",
-                        type, type2, type3, val);
-            break;
-    }
-
-    return 0;
-}
-
 /*==========================================
  * スクリプトによるスキル所得
  *------------------------------------------
@@ -2982,9 +2724,6 @@ int pc_setpos(struct map_session_data *sd, const char *mapname_org, int x, int y
         skill_gangsterparadise(sd, 0);
     }
 
-    if (bool(sd->status.option & Option::HIDE2))
-        skill_status_change_end(&sd->bl, SC_HIDING, -1);
-
     memcpy(mapname, mapname_org, 24);
     mapname[16] = 0;
     if (strstr(mapname, ".gat") == NULL && strlen(mapname) < 16)
@@ -3002,7 +2741,6 @@ int pc_setpos(struct map_session_data *sd, const char *mapname_org, int x, int y
             if (map_mapname2ipport(mapname, &ip, &port) == 0)
             {
                 skill_stop_dancing(&sd->bl, 1);
-                skill_unit_out_all(&sd->bl, gettick(), 1);
                 clif_clearchar_area(&sd->bl, clrtype & 0xffff);
                 skill_gangsterparadise(sd, 0);
                 map_delblock(&sd->bl);
@@ -3047,7 +2785,6 @@ int pc_setpos(struct map_session_data *sd, const char *mapname_org, int x, int y
 
     if (sd->mapname[0] && sd->bl.prev != NULL)
     {
-        skill_unit_out_all(&sd->bl, gettick(), 1);
         clif_clearchar_area(&sd->bl, clrtype & 0xffff);
         skill_gangsterparadise(sd, 0);
         map_delblock(&sd->bl);
@@ -3135,7 +2872,7 @@ int calc_next_walk_step(struct map_session_data *sd)
 
     if (sd->walkpath.path_pos >= sd->walkpath.path_len)
         return -1;
-    if (sd->walkpath.path[sd->walkpath.path_pos] & 1)
+    if (dir_is_diagonal(sd->walkpath.path[sd->walkpath.path_pos]))
         return sd->speed * 14 / 10;
 
     return sd->speed;
@@ -3184,7 +2921,7 @@ void pc_walk(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
     }
     else
     {                           // マス目境界へ到着
-        if (sd->walkpath.path[sd->walkpath.path_pos] >= 8)
+        if (sd->walkpath.path[sd->walkpath.path_pos] >= DIR::COUNT)
             return;
 
         x = sd->bl.x;
@@ -3196,8 +2933,8 @@ void pc_walk(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
             return;
         }
         sd->dir = sd->head_dir = sd->walkpath.path[sd->walkpath.path_pos];
-        dx = dirx[(int) sd->dir];
-        dy = diry[(int) sd->dir];
+        dx = dirx[sd->dir];
+        dy = diry[sd->dir];
         ctype = map_getcell(sd->bl.m, x + dx, y + dy);
         if (ctype == 1 || ctype == 5)
         {
@@ -3247,9 +2984,7 @@ void pc_walk(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
                     sd->party_hp = -1;
             }
         }
-        // クローキングの消滅検査
-        if (bool(sd->status.option & Option::CLOAK))
-            skill_check_cloaking(&sd->bl);
+
         // ディボーション検査
         for (i = 0; i < 5; i++)
             if (sd->dev.val1[i])
@@ -3258,8 +2993,6 @@ void pc_walk(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
                 break;
             }
 
-        skill_unit_move(&sd->bl, tick, 1); // スキルユニットの検査
-
         if (map_getcell(sd->bl.m, x, y) & 0x80)
             npc_touch_areanpc(sd, sd->bl.m, x, y);
         else
@@ -3377,7 +3110,7 @@ void pc_touch_all_relevant_npcs(struct map_session_data *sd)
 int pc_movepos(struct map_session_data *sd, int dst_x, int dst_y)
 {
     int moveblock;
-    int dx, dy, dist;
+    int dx, dy;
 
     struct walkpath_data wpd;
 
@@ -3390,7 +3123,6 @@ int pc_movepos(struct map_session_data *sd, int dst_x, int dst_y)
 
     dx = dst_x - sd->bl.x;
     dy = dst_y - sd->bl.y;
-    dist = distance(sd->bl.x, sd->bl.y, dst_x, dst_y);
 
     moveblock = (sd->bl.x / BLOCK_SIZE != dst_x / BLOCK_SIZE
                  || sd->bl.y / BLOCK_SIZE != dst_y / BLOCK_SIZE);
@@ -3430,12 +3162,6 @@ int pc_movepos(struct map_session_data *sd, int dst_x, int dst_y)
         }
     }
 
-    // クローキングの消滅検査
-    if (bool(sd->status.option & Option::CLOAK))
-        skill_check_cloaking(&sd->bl);
-
-    skill_unit_move(&sd->bl, gettick(), dist + 7);    // スキルユニットの検査
-
     pc_touch_all_relevant_npcs(sd);
     return 0;
 }
@@ -3515,17 +3241,13 @@ void pc_attack_timer(timer_id tid, tick_t tick, custom_id_t id, custom_data_t)
         return;
 
     // 異常などで攻撃できない
-    if (sd->opt1 != Opt1::ZERO
-        || bool(sd->status.option & (Option::OLD_ANY_HIDE)))
+    if (sd->opt1 != Opt1::ZERO)
         return;
 
     Option *opt = battle_get_option(bl);
     if (opt != NULL && bool(*opt & Option::REAL_ANY_HIDE))
         return;
 
-    if (sd->skilltimer != -1)
-        return;
-
     if (!battle_config.sdelay_attack_enable)
     {
         if (DIFF_TICK(tick, sd->canact_tick) < 0)
@@ -4192,9 +3914,6 @@ int pc_damage(struct block_list *src, struct map_session_data *sd,
 
     sd->status.hp -= damage;
 
-    if (bool(sd->status.option & Option::HIDE2))
-        skill_status_change_end(&sd->bl, SC_HIDING, -1);
-
     if (sd->status.hp > 0)
     {
         // まだ生きているならHP更新
@@ -4227,7 +3946,6 @@ int pc_damage(struct block_list *src, struct map_session_data *sd,
     pc_stop_walking(sd, 0);
     skill_castcancel(&sd->bl, 0);  // 詠唱の中止
     clif_clearchar_area(&sd->bl, 1);
-    skill_unit_out_all(&sd->bl, gettick(), 1);
     pc_setglobalreg(sd, "PC_DIE_COUNTER", ++sd->die_counter);  //死にカウンター書き込み
     skill_status_change_clear(&sd->bl, 0); // ステータス異常を解除する
     clif_updatestatus(sd, SP_HP);
@@ -4476,9 +4194,6 @@ int pc_readparam(struct map_session_data *sd, SP type)
         case SP_LUK:
             val = sd->status.attrs[sp_to_attr(type)];
             break;
-        case SP_FAME:
-            val = sd->fame;
-            break;
     }
 
     return val;
@@ -4595,9 +4310,6 @@ int pc_setparam(struct map_session_data *sd, SP type, int val)
         case SP_LUK:
             sd->status.attrs[sp_to_attr(type)] = val;
             break;
-        case SP_FAME:
-            sd->fame = val;
-            break;
     }
     clif_updatestatus(sd, type);
 
@@ -4734,13 +4446,6 @@ int pc_itemheal_effect(struct map_session_data *sd, int hp, int sp)
 {
     nullpo_ret(sd);
 
-    if (sd->state.potionpitcher_flag)
-    {
-        sd->potion_hp = hp;
-        sd->potion_sp = sp;
-        return 0;
-    }
-
     if (pc_checkoverhp(sd))
     {
         if (hp > 0)
@@ -4791,13 +4496,6 @@ int pc_percentheal(struct map_session_data *sd, int hp, int sp)
 {
     nullpo_ret(sd);
 
-    if (sd->state.potionpitcher_flag)
-    {
-        sd->potion_per_hp = hp;
-        sd->potion_per_sp = sp;
-        return 0;
-    }
-
     if (pc_checkoverhp(sd))
     {
         if (hp > 0)
@@ -5742,7 +5440,8 @@ int pc_calc_pvprank(struct map_session_data *sd)
     struct map_data *m;
 
     nullpo_ret(sd);
-    nullpo_ret(m = &map[sd->bl.m]);
+    m = &map[sd->bl.m];
+    nullpo_ret(m);
 
     if (!(m->flag.pvp))
         return 0;
@@ -6117,7 +5816,7 @@ void pc_natural_heal_sub(struct map_session_data *sd)
          || battle_config.natural_heal_weight_rate > 100
          || sd->weight * 100 / sd->max_weight <
          battle_config.natural_heal_weight_rate) && !pc_isdead(sd)
-        && !pc_ishiding(sd) && sd->sc_data[SC_POISON].timer == -1)
+        && sd->sc_data[SC_POISON].timer == -1)
     {
         pc_natural_heal_hp(sd);
         pc_natural_heal_sp(sd);
diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index 6670293..9b0f4ef 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -22,7 +22,7 @@ bool pc_issit(struct map_session_data *sd)
     return sd->state.dead_sit == 2;
 }
 inline
-void pc_setdir(struct map_session_data *sd, int b)
+void pc_setdir(struct map_session_data *sd, DIR b)
 {
     sd->dir = (b);
 }
@@ -32,11 +32,6 @@ void pc_setchatid(struct map_session_data *sd, int n)
     sd->chatID = n;
 }
 inline
-bool pc_ishiding(struct map_session_data *sd)
-{
-    return bool(sd->status.option & Option::OLD_ANY_HIDE);
-}
-inline
 bool pc_isinvisible(struct map_session_data *sd)
 {
     return bool(sd->status.option & Option::HIDE);
@@ -98,7 +93,6 @@ int pc_checkweighticon(struct map_session_data *sd);
 int pc_calcstatus(struct map_session_data *, int);
 int pc_bonus(struct map_session_data *, SP, int);
 int pc_bonus2(struct map_session_data *sd, SP, int, int);
-int pc_bonus3(struct map_session_data *sd, SP, int, int, int);
 int pc_skill(struct map_session_data *, SkillID, int, int);
 
 int pc_steal_item(struct map_session_data *sd, struct block_list *bl);
diff --git a/src/map/script.cpp b/src/map/script.cpp
index 4304640..c7bd9cd 100644
--- a/src/map/script.cpp
+++ b/src/map/script.cpp
@@ -3232,9 +3232,6 @@ void builtin_sc_start(ScriptState *st)
         bl = map_id2bl(conv_num(st, &(st->stack->stack_data[st->start + 5])));
     else
         bl = map_id2bl(st->rid);
-    if (bl->type == BL_PC
-        && ((struct map_session_data *) bl)->state.potionpitcher_flag)
-        bl = map_id2bl(((struct map_session_data *) bl)->skilltarget);
     skill_status_change_start(bl, type, val1, 0, 0, 0, tick, 0);
 }
 
@@ -3248,9 +3245,6 @@ void builtin_sc_end(ScriptState *st)
     struct block_list *bl;
     StatusChange type = StatusChange(conv_num(st, &(st->stack->stack_data[st->start + 2])));
     bl = map_id2bl(st->rid);
-    if (bl->type == BL_PC
-        && ((struct map_session_data *) bl)->state.potionpitcher_flag)
-        bl = map_id2bl(((struct map_session_data *) bl)->skilltarget);
     skill_status_change_end(bl, type, -1);
 //  if(battle_config.etc_log)
 //      PRINTF("sc_end : %d %d\n",st->rid,type);
@@ -3262,9 +3256,6 @@ void builtin_sc_check(ScriptState *st)
     struct block_list *bl;
     StatusChange type = StatusChange(conv_num(st, &(st->stack->stack_data[st->start + 2])));
     bl = map_id2bl(st->rid);
-    if (bl->type == BL_PC
-        && ((struct map_session_data *) bl)->state.potionpitcher_flag)
-        bl = map_id2bl(((struct map_session_data *) bl)->skilltarget);
 
     push_val(st->stack, ScriptCode::INT, skill_status_change_active(bl, type));
 
diff --git a/src/map/skill.cpp b/src/map/skill.cpp
index aac7e1f..a93f375 100644
--- a/src/map/skill.cpp
+++ b/src/map/skill.cpp
@@ -18,478 +18,6 @@
 
 #include "../poison.hpp"
 
-#define SKILLUNITTIMER_INVERVAL 100
-
-// This table is wrong.
-// The only used skill with a status effect is NPC_SELFDESTRUCT,
-// and due to the misnumber, it wasn't active anyway.
-static __attribute__((deprecated))
-earray<StatusChange, SkillID, MAX_SKILL_DB> SkillStatusChangeTable //=
-{{
-    // 0-
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // NV_BASIC
-    StatusChange::NEGATIVE1,    // SM_SWORD
-    StatusChange::NEGATIVE1,    // SM_TWOHAND
-    StatusChange::NEGATIVE1,    // SM_RECOVERY
-    StatusChange::NEGATIVE1,    // SM_BASH
-    StatusChange::NEGATIVE1,    // SM_PROVOKE
-    StatusChange::NEGATIVE1,    // SM_MAGNUM
-    StatusChange::NEGATIVE1,    // SM_ENDURE
-    StatusChange::NEGATIVE1,    // MG_SRECOVERY
-    // 10-
-    StatusChange::NEGATIVE1,    // MG_SIGHT
-    StatusChange::NEGATIVE1,    // MG_NAPALMBEAT
-    StatusChange::NEGATIVE1,    // MG_SAFETYWALL
-    StatusChange::NEGATIVE1,    // MG_SOULSTRIKE
-    StatusChange::NEGATIVE1,    // MG_COLDBOLT
-    StatusChange::NEGATIVE1,    // MG_FROSTDIVER
-    StatusChange::NEGATIVE1,    // MG_STONECURSE
-    StatusChange::NEGATIVE1,    // MG_FIREBALL
-    StatusChange::NEGATIVE1,    // MG_FIREWALL
-    StatusChange::NEGATIVE1,    // MG_FIREBOLT
-    // 20-
-    StatusChange::NEGATIVE1,    // MG_LIGHTNINGBOLT
-    StatusChange::NEGATIVE1,    // MG_THUNDERSTORM
-    StatusChange::NEGATIVE1,    // AL_DP
-    StatusChange::NEGATIVE1,    // AL_DEMONBANE
-    StatusChange::NEGATIVE1,    // AL_RUWACH
-    StatusChange::NEGATIVE1,    // AL_PNEUMA
-    StatusChange::NEGATIVE1,    // AL_TELEPORT
-    StatusChange::NEGATIVE1,    // AL_WARP
-    StatusChange::NEGATIVE1,    // AL_HEAL
-    StatusChange::NEGATIVE1,    // AL_INCAGI
-    // 30-
-    StatusChange::NEGATIVE1,    // AL_DECAGI
-    StatusChange::NEGATIVE1,    // AL_HOLYWATER
-    StatusChange::NEGATIVE1,    // AL_CRUCIS
-    StatusChange::NEGATIVE1,    // AL_ANGELUS
-    StatusChange::NEGATIVE1,    // AL_BLESSING
-    StatusChange::NEGATIVE1,    // AL_CURE
-    StatusChange::NEGATIVE1,    // MC_INCCARRY
-    StatusChange::NEGATIVE1,    // MC_DISCOUNT
-    StatusChange::NEGATIVE1,    // MC_OVERCHARGE
-    StatusChange::NEGATIVE1,    // MC_PUSHCART
-    // 40-
-    StatusChange::NEGATIVE1,    // MC_IDENTIFY
-    StatusChange::NEGATIVE1,    // MC_VENDING
-    StatusChange::NEGATIVE1,    // MC_MAMMONITE
-    StatusChange::NEGATIVE1,    // AC_OWL
-    StatusChange::NEGATIVE1,    // AC_VULTURE
-    StatusChange::NEGATIVE1,    // AC_CONCENTRATION
-    StatusChange::NEGATIVE1,    // AC_DOUBLE
-    StatusChange::NEGATIVE1,    // AC_SHOWER
-    StatusChange::NEGATIVE1,    // TF_DOUBLE
-    StatusChange::NEGATIVE1,    // TF_MISS
-    // 50-
-    StatusChange::NEGATIVE1,    // TF_STEAL
-    StatusChange::NEGATIVE1,    // TF_HIDING
-    StatusChange::NEGATIVE1,    // TF_POISON
-    StatusChange::NEGATIVE1,    // TF_DETOXIFY
-    StatusChange::NEGATIVE1,    // ALL_RESURRECTION
-    StatusChange::NEGATIVE1,    // KN_SPEARMASTERY
-    StatusChange::NEGATIVE1,    // KN_PIERCE
-    StatusChange::NEGATIVE1,    // KN_BRANDISHSPEAR
-    StatusChange::NEGATIVE1,    // KN_SPEARSTAB
-    StatusChange::NEGATIVE1,    // KN_SPEARBOOMERANG
-    // 60-
-    StatusChange::NEGATIVE1,    // KN_TWOHANDQUICKEN
-    StatusChange::NEGATIVE1,    // KN_AUTOCOUNTER
-    StatusChange::NEGATIVE1,    // KN_BOWLINGBASH
-    StatusChange::NEGATIVE1,    // KN_RIDING
-    StatusChange::NEGATIVE1,    // KN_CAVALIERMASTERY
-    StatusChange::NEGATIVE1,    // PR_MACEMASTERY
-    StatusChange::NEGATIVE1,    // PR_IMPOSITIO
-    StatusChange::NEGATIVE1,    // PR_SUFFRAGIUM
-    StatusChange::NEGATIVE1,    // PR_ASPERSIO
-    StatusChange::NEGATIVE1,    // PR_BENEDICTIO
-    // 70-
-    StatusChange::NEGATIVE1,    // PR_SANCTUARY
-    StatusChange::NEGATIVE1,    // PR_SLOWPOISON
-    StatusChange::NEGATIVE1,    // PR_STRECOVERY
-    StatusChange::NEGATIVE1,    // PR_KYRIE
-    StatusChange::NEGATIVE1,    // PR_MAGNIFICAT
-    StatusChange::NEGATIVE1,    // PR_GLORIA
-    StatusChange::NEGATIVE1,    // PR_LEXDIVINA
-    StatusChange::NEGATIVE1,    // PR_TURNUNDEAD
-    StatusChange::NEGATIVE1,    // PR_LEXAETERNA
-    StatusChange::NEGATIVE1,    // PR_MAGNUS
-    // 80-
-    StatusChange::NEGATIVE1,    // WZ_FIREPILLAR
-    StatusChange::NEGATIVE1,    // WZ_SIGHTRASHER
-    StatusChange::NEGATIVE1,    // WZ_FIREIVY
-    StatusChange::NEGATIVE1,    // WZ_METEOR
-    StatusChange::NEGATIVE1,    // WZ_JUPITEL
-    StatusChange::NEGATIVE1,    // WZ_VERMILION
-    StatusChange::NEGATIVE1,    // WZ_WATERBALL
-    StatusChange::NEGATIVE1,    // WZ_ICEWALL
-    StatusChange::NEGATIVE1,    // WZ_FROSTNOVA
-    StatusChange::NEGATIVE1,    // WZ_STORMGUST
-    // 90-
-    StatusChange::NEGATIVE1,    // WZ_EARTHSPIKE
-    StatusChange::NEGATIVE1,    // WZ_HEAVENDRIVE
-    StatusChange::NEGATIVE1,    // WZ_QUAGMIRE
-    StatusChange::NEGATIVE1,    // WZ_ESTIMATION
-    StatusChange::NEGATIVE1,    // BS_IRON
-    StatusChange::NEGATIVE1,    // BS_STEEL
-    StatusChange::NEGATIVE1,    // BS_ENCHANTEDSTONE
-    StatusChange::NEGATIVE1,    // BS_ORIDEOCON
-    StatusChange::NEGATIVE1,    // BS_DAGGER
-    StatusChange::NEGATIVE1,    // BS_SWORD
-    // 100-
-    StatusChange::NEGATIVE1,    // BS_TWOHANDSWORD
-    StatusChange::NEGATIVE1,    // BS_AXE
-    StatusChange::NEGATIVE1,    // BS_MACE
-    StatusChange::NEGATIVE1,    // BS_KNUCKLE
-    StatusChange::NEGATIVE1,    // BS_SPEAR
-    StatusChange::NEGATIVE1,    // BS_HILTBINDING
-    StatusChange::NEGATIVE1,    // BS_FINDINGORE
-    StatusChange::NEGATIVE1,    // BS_WEAPONRESEARCH
-    StatusChange::NEGATIVE1,    // BS_REPAIRWEAPON
-    StatusChange::NEGATIVE1,    // BS_SKINTEMPER
-    // 110-
-    StatusChange::NEGATIVE1,    // BS_HAMMERFALL
-    StatusChange::NEGATIVE1,    // BS_ADRENALINE
-    StatusChange::NEGATIVE1,    // BS_WEAPONPERFECT
-    StatusChange::NEGATIVE1,    // BS_OVERTHRUST
-    StatusChange::NEGATIVE1,    // BS_MAXIMIZE
-    StatusChange::NEGATIVE1,    // HT_SKIDTRAP
-    StatusChange::NEGATIVE1,    // HT_LANDMINE
-    StatusChange::NEGATIVE1,    // HT_ANKLESNARE
-    StatusChange::NEGATIVE1,    // HT_SHOCKWAVE
-    StatusChange::NEGATIVE1,    // HT_SANDMAN
-    // 120-
-    StatusChange::NEGATIVE1,    // HT_FLASHER
-    StatusChange::NEGATIVE1,    // HT_FREEZINGTRAP
-    StatusChange::NEGATIVE1,    // HT_BLASTMINE
-    StatusChange::NEGATIVE1,    // HT_CLAYMORETRAP
-    StatusChange::NEGATIVE1,    // HT_REMOVETRAP
-    StatusChange::NEGATIVE1,    // HT_TALKIEBOX
-    StatusChange::NEGATIVE1,    // HT_BEASTBANE
-    StatusChange::NEGATIVE1,    // HT_FALCON
-    StatusChange::NEGATIVE1,    // HT_STEELCROW
-    StatusChange::NEGATIVE1,    // HT_BLITZBEAT
-    // 130-
-    StatusChange::NEGATIVE1,    // HT_DETECTING
-    StatusChange::NEGATIVE1,    // HT_SPRINGTRAP
-    StatusChange::NEGATIVE1,    // AS_RIGHT
-    StatusChange::NEGATIVE1,    // AS_LEFT
-    StatusChange::NEGATIVE1,    // AS_KATAR
-    StatusChange::NEGATIVE1,    // AS_CLOAKING
-    StatusChange::NEGATIVE1,    // AS_SONICBLOW
-    StatusChange::NEGATIVE1,    // AS_GRIMTOOTH
-    StatusChange::NEGATIVE1,    // AS_ENCHANTPOISON
-    StatusChange::NEGATIVE1,    // AS_POISONREACT
-    // 140-
-    StatusChange::NEGATIVE1,    // AS_VENOMDUST
-    StatusChange::NEGATIVE1,    // AS_SPLASHER
-    StatusChange::NEGATIVE1,    // NV_FIRSTAID
-    StatusChange::NEGATIVE1,    // NV_TRICKDEAD
-    StatusChange::NEGATIVE1,    // SM_MOVINGRECOVERY
-    StatusChange::NEGATIVE1,    // SM_FATALBLOW
-    StatusChange::NEGATIVE1,    // SM_AUTOBERSERK
-    StatusChange::NEGATIVE1,    // AC_MAKINGARROW
-    StatusChange::NEGATIVE1,    // AC_CHARGEARROW
-    StatusChange::NEGATIVE1,    // TF_SPRINKLESAND
-    // 150-
-    StatusChange::NEGATIVE1,    // TF_BACKSLIDING
-    StatusChange::NEGATIVE1,    // TF_PICKSTONE
-    StatusChange::NEGATIVE1,    // TF_THROWSTONE
-    StatusChange::NEGATIVE1,    // MC_CARTREVOLUTION
-    StatusChange::NEGATIVE1,    // MC_CHANGECART
-    StatusChange::NEGATIVE1,    // MC_LOUD
-    StatusChange::NEGATIVE1,    // AL_HOLYLIGHT
-    StatusChange::NEGATIVE1,    // MG_ENERGYCOAT
-    StatusChange::NEGATIVE1,    // NPC_PIERCINGATT
-    StatusChange::NEGATIVE1,    // NPC_MENTALBREAKER
-    // 160-
-    StatusChange::NEGATIVE1,    // NPC_RANGEATTACK
-    StatusChange::NEGATIVE1,    // NPC_ATTRICHANGE
-    StatusChange::NEGATIVE1,    // NPC_CHANGEWATER
-    StatusChange::NEGATIVE1,    // NPC_CHANGEGROUND
-    StatusChange::NEGATIVE1,    // NPC_CHANGEFIRE
-    StatusChange::NEGATIVE1,    // NPC_CHANGEWIND
-    StatusChange::NEGATIVE1,    // NPC_CHANGEPOISON
-    StatusChange::NEGATIVE1,    // NPC_CHANGEHOLY
-    StatusChange::NEGATIVE1,    // NPC_CHANGEDARKNESS
-    StatusChange::NEGATIVE1,    // NPC_CHANGETELEKINESIS
-    // 170-
-    StatusChange::NEGATIVE1,    // NPC_CRITICALSLASH
-    StatusChange::NEGATIVE1,    // NPC_COMBOATTACK
-    StatusChange::NEGATIVE1,    // NPC_GUIDEDATTACK
-    SC_SELFDESTRUCTION,         // NPC_SELFDESTRUCTION
-    StatusChange::NEGATIVE1,    // NPC_SPLASHATTACK
-    StatusChange::NEGATIVE1,    // NPC_SUICIDE
-    StatusChange::NEGATIVE1,    // NPC_POISON
-    StatusChange::NEGATIVE1,    // NPC_BLINDATTACK
-    StatusChange::NEGATIVE1,    // NPC_SILENCEATTACK
-    StatusChange::NEGATIVE1,    // NPC_STUNATTACK
-    // 180-
-    StatusChange::NEGATIVE1,    // NPC_PETRIFYATTACK
-    StatusChange::NEGATIVE1,    // NPC_CURSEATTACK
-    StatusChange::NEGATIVE1,    // NPC_SLEEPATTACK
-    StatusChange::NEGATIVE1,    // NPC_RANDOMATTACK
-    StatusChange::NEGATIVE1,    // NPC_WATERATTACK
-    StatusChange::NEGATIVE1,    // NPC_GROUNDATTACK
-    StatusChange::NEGATIVE1,    // NPC_FIREATTACK
-    StatusChange::NEGATIVE1,    // NPC_WINDATTACK
-    StatusChange::NEGATIVE1,    // NPC_POISONATTACK
-    StatusChange::NEGATIVE1,    // NPC_HOLYATTACK
-    // 190-
-    StatusChange::NEGATIVE1,    // NPC_DARKNESSATTACK
-    StatusChange::NEGATIVE1,    // NPC_TELEKINESISATTACK
-    StatusChange::NEGATIVE1,    // NPC_MAGICALATTACK
-    StatusChange::NEGATIVE1,    // NPC_METAMORPHOSIS
-    StatusChange::NEGATIVE1,    // NPC_PROVOCATION
-    StatusChange::NEGATIVE1,    // NPC_SMOKING
-    StatusChange::NEGATIVE1,    // NPC_SUMMONSLAVE
-    StatusChange::NEGATIVE1,    // NPC_EMOTION
-    StatusChange::NEGATIVE1,    // NPC_TRANSFORMATION
-    StatusChange::NEGATIVE1,    // NPC_BLOODDRAIN
-    // 200-
-    StatusChange::NEGATIVE1,    // NPC_ENERGYDRAIN
-    StatusChange::NEGATIVE1,    // NPC_KEEPING
-    StatusChange::NEGATIVE1,    // NPC_DARKBREATH
-    StatusChange::NEGATIVE1,    // NPC_DARKBLESSING
-    StatusChange::NEGATIVE1,    // NPC_BARRIER
-    StatusChange::NEGATIVE1,    // NPC_DEFENDER
-    StatusChange::NEGATIVE1,    // NPC_LICK
-    StatusChange::NEGATIVE1,    // NPC_HALLUCINATION
-    StatusChange::NEGATIVE1,    // NPC_REBIRTH
-    StatusChange::NEGATIVE1,    // NPC_SUMMONMONSTER
-    // 210-
-    StatusChange::NEGATIVE1,    // RG_SNATCHER
-    StatusChange::NEGATIVE1,    // RG_STEALCOIN
-    StatusChange::NEGATIVE1,    // RG_BACKSTAP
-    StatusChange::NEGATIVE1,    // RG_TUNNELDRIVE
-    StatusChange::NEGATIVE1,    // RG_RAID
-    StatusChange::NEGATIVE1,    // RG_STRIPWEAPON
-    StatusChange::NEGATIVE1,    // RG_STRIPSHIELD
-    StatusChange::NEGATIVE1,    // RG_STRIPARMOR
-    StatusChange::NEGATIVE1,    // RG_STRIPHELM
-    StatusChange::NEGATIVE1,    // RG_INTIMIDATE
-    // 220-
-    StatusChange::NEGATIVE1,    // RG_GRAFFITI
-    StatusChange::NEGATIVE1,    // RG_FLAGGRAFFITI
-    StatusChange::NEGATIVE1,    // RG_CLEANER
-    StatusChange::NEGATIVE1,    // RG_GANGSTER
-    StatusChange::NEGATIVE1,    // RG_COMPULSION
-    StatusChange::NEGATIVE1,    // RG_PLAGIARISM
-    StatusChange::NEGATIVE1,    // AM_AXEMASTERY
-    StatusChange::NEGATIVE1,    // AM_LEARNINGPOTION
-    StatusChange::NEGATIVE1,    // AM_PHARMACY
-    StatusChange::NEGATIVE1,    // AM_DEMONSTRATION
-    // 230-
-    StatusChange::NEGATIVE1,    // AM_ACIDTERROR
-    StatusChange::NEGATIVE1,    // AM_POTIONPITCHER
-    StatusChange::NEGATIVE1,    // AM_CANNIBALIZE
-    StatusChange::NEGATIVE1,    // AM_SPHEREMINE
-    StatusChange::NEGATIVE1,    // AM_CP_WEAPON
-    StatusChange::NEGATIVE1,    // AM_CP_SHIELD
-    StatusChange::NEGATIVE1,    // AM_CP_ARMOR
-    StatusChange::NEGATIVE1,    // AM_CP_HELM
-    StatusChange::NEGATIVE1,    // AM_BIOETHICS
-    StatusChange::NEGATIVE1,    // AM_BIOTECHNOLOGY
-    // 240-
-    StatusChange::NEGATIVE1,    // AM_CREATECREATURE
-    StatusChange::NEGATIVE1,    // AM_CULTIVATION
-    StatusChange::NEGATIVE1,    // AM_FLAMECONTROL
-    StatusChange::NEGATIVE1,    // AM_CALLHOMUN
-    StatusChange::NEGATIVE1,    // AM_REST
-    StatusChange::NEGATIVE1,    // AM_DRILLMASTER
-    StatusChange::NEGATIVE1,    // AM_HEALHOMUN
-    StatusChange::NEGATIVE1,    // AM_RESURRECTHOMUN
-    StatusChange::NEGATIVE1,    // CR_TRUST
-    StatusChange::NEGATIVE1,    // CR_AUTOGUARD
-    // 250-
-    StatusChange::NEGATIVE1,    // CR_SHIELDCHARGE
-    StatusChange::NEGATIVE1,    // CR_SHIELDBOOMERANG
-    StatusChange::NEGATIVE1,    // CR_REFLECTSHIELD
-    StatusChange::NEGATIVE1,    // CR_HOLYCROSS
-    StatusChange::NEGATIVE1,    // CR_GRANDCROSS
-    StatusChange::NEGATIVE1,    // CR_DEVOTION
-    StatusChange::NEGATIVE1,    // CR_PROVIDENCE
-    StatusChange::NEGATIVE1,    // CR_DEFENDER
-    StatusChange::NEGATIVE1,    // CR_SPEARQUICKEN
-    StatusChange::NEGATIVE1,    // MO_IRONHAND
-    // 260-
-    StatusChange::NEGATIVE1,    // MO_SPIRITSRECOVERY
-    StatusChange::NEGATIVE1,    // MO_CALLSPIRITS
-    StatusChange::NEGATIVE1,    // MO_ABSORBSPIRITS
-    StatusChange::NEGATIVE1,    // MO_TRIPLEATTACK
-    StatusChange::NEGATIVE1,    // MO_BODYRELOCATION
-    StatusChange::NEGATIVE1,    // MO_DODGE
-    StatusChange::NEGATIVE1,    // MO_INVESTIGATE
-    StatusChange::NEGATIVE1,    // MO_FINGEROFFENSIVE
-    StatusChange::NEGATIVE1,    // MO_STEELBODY
-    StatusChange::NEGATIVE1,    // MO_BLADESTOP
-    // 270-
-    StatusChange::NEGATIVE1,    // MO_EXPLOSIONSPIRITS
-    StatusChange::NEGATIVE1,    // MO_EXTREMITYFIST
-    StatusChange::NEGATIVE1,    // MO_CHAINCOMBO
-    StatusChange::NEGATIVE1,    // MO_COMBOFINISH
-    StatusChange::NEGATIVE1,    // SA_ADVANCEDBOOK
-    StatusChange::NEGATIVE1,    // SA_CASTCANCEL
-    StatusChange::NEGATIVE1,    // SA_MAGICROD
-    StatusChange::NEGATIVE1,    // SA_SPELLBREAKER
-    StatusChange::NEGATIVE1,    // SA_FREECAST
-    StatusChange::NEGATIVE1,    // SA_AUTOSPELL
-    // 280-
-    StatusChange::NEGATIVE1,    // SA_FLAMELAUNCHER
-    StatusChange::NEGATIVE1,    // SA_FROSTWEAPON
-    StatusChange::NEGATIVE1,    // SA_LIGHTNINGLOADER
-    StatusChange::NEGATIVE1,    // SA_SEISMICWEAPON
-    StatusChange::NEGATIVE1,    // SA_DRAGONOLOGY
-    StatusChange::NEGATIVE1,    // SA_VOLCANO
-    StatusChange::NEGATIVE1,    // SA_DELUGE
-    StatusChange::NEGATIVE1,    // SA_VIOLENTGALE
-    StatusChange::NEGATIVE1,    // SA_LANDPROTECTOR
-    StatusChange::NEGATIVE1,    // SA_DISPELL
-    // 290-
-    StatusChange::NEGATIVE1,    // SA_ABRACADABRA
-    StatusChange::NEGATIVE1,    // SA_MONOCELL
-    StatusChange::NEGATIVE1,    // SA_CLASSCHANGE
-    StatusChange::NEGATIVE1,    // SA_SUMMONMONSTER
-    StatusChange::NEGATIVE1,    // SA_REVERSEORCISH
-    StatusChange::NEGATIVE1,    // SA_DEATH
-    StatusChange::NEGATIVE1,    // SA_FORTUNE
-    StatusChange::NEGATIVE1,    // SA_TAMINGMONSTER
-    StatusChange::NEGATIVE1,    // SA_QUESTION
-    StatusChange::NEGATIVE1,    // SA_GRAVITY
-    // 300-
-    StatusChange::NEGATIVE1,    // SA_LEVELUP
-    StatusChange::NEGATIVE1,    // SA_INSTANTDEATH
-    StatusChange::NEGATIVE1,    // SA_FULLRECOVERY
-    StatusChange::NEGATIVE1,    // SA_COMA
-    StatusChange::NEGATIVE1,    // BD_ADAPTATION
-    StatusChange::NEGATIVE1,    // BD_ENCORE
-    StatusChange::NEGATIVE1,    // BD_LULLABY
-    StatusChange::NEGATIVE1,    // BD_RICHMANKIM
-    StatusChange::NEGATIVE1,    // BD_ETERNALCHAOS
-    StatusChange::NEGATIVE1,    // BD_DRUMBATTLEFIELD
-    // 310-
-    StatusChange::NEGATIVE1,    // BD_RINGNIBELUNGEN
-    StatusChange::NEGATIVE1,    // BD_ROKISWEIL
-    StatusChange::NEGATIVE1,    // BD_INTOABYSS
-    StatusChange::NEGATIVE1,    // BD_SIEGFRIED
-    StatusChange::NEGATIVE1,    // BD_RAGNAROK
-    StatusChange::NEGATIVE1,    // BA_MUSICALLESSON
-    StatusChange::NEGATIVE1,    // BA_MUSICALSTRIKE
-    StatusChange::NEGATIVE1,    // BA_DISSONANCE
-    StatusChange::NEGATIVE1,    // BA_FROSTJOKE
-    StatusChange::NEGATIVE1,    // BA_WHISTLE
-    // 320-
-    StatusChange::NEGATIVE1,    // BA_ASSASSINCROSS
-    StatusChange::NEGATIVE1,    // BA_POEMBRAGI
-    StatusChange::NEGATIVE1,    // BA_APPLEIDUN
-    StatusChange::NEGATIVE1,    // DC_DANCINGLESSON
-    StatusChange::NEGATIVE1,    // DC_THROWARROW
-    StatusChange::NEGATIVE1,    // DC_UGLYDANCE
-    StatusChange::NEGATIVE1,    // DC_SCREAM
-    StatusChange::NEGATIVE1,    // DC_HUMMING
-    StatusChange::NEGATIVE1,    // DC_DONTFORGETME
-    StatusChange::NEGATIVE1,    // DC_FORTUNEKISS
-    // 330-
-    StatusChange::NEGATIVE1,    // DC_SERVICEFORYOU
-    StatusChange::NEGATIVE1,    // NPC_SELFDESTRUCTION2
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // WE_MALE
-    StatusChange::NEGATIVE1,    // WE_FEMALE
-    StatusChange::NEGATIVE1,    // WE_CALLPARTNER
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // NPC_DARKCROSS
-    StatusChange::NEGATIVE1,    // (none)
-    // 340-
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    // 350-
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // (none)
-    StatusChange::NEGATIVE1,    // LK_AURABLADE
-    StatusChange::NEGATIVE1,    // LK_PARRYING
-    StatusChange::NEGATIVE1,    // LK_CONCENTRATION
-    StatusChange::NEGATIVE1,    // LK_TENSIONRELAX
-    StatusChange::NEGATIVE1,    // LK_BERSERK
-    // 360-
-    StatusChange::NEGATIVE1,    // LK_FURY
-    StatusChange::NEGATIVE1,    // HP_ASSUMPTIO
-    StatusChange::NEGATIVE1,    // HP_BASILICA
-    StatusChange::NEGATIVE1,    // HP_MEDITATIO
-    StatusChange::NEGATIVE1,    // HW_SOULDRAIN
-    StatusChange::NEGATIVE1,    // HW_MAGICCRASHER
-    StatusChange::NEGATIVE1,    // HW_MAGICPOWER
-    StatusChange::NEGATIVE1,    // PA_PRESSURE
-    StatusChange::NEGATIVE1,    // PA_SACRIFICE
-    StatusChange::NEGATIVE1,    // PA_GOSPEL
-    // 370-
-    StatusChange::NEGATIVE1,    // CH_PALMSTRIKE
-    StatusChange::NEGATIVE1,    // CH_TIGERFIST
-    StatusChange::NEGATIVE1,    // CH_CHAINCRUSH
-    StatusChange::NEGATIVE1,    // PF_HPCONVERSION
-    StatusChange::NEGATIVE1,    // PF_SOULCHANGE
-    StatusChange::NEGATIVE1,    // PF_SOULBURN
-    StatusChange::NEGATIVE1,    // ASC_KATAR
-    StatusChange::NEGATIVE1,    // ASC_HALLUCINATION
-    StatusChange::NEGATIVE1,    // ASC_EDP
-    StatusChange::NEGATIVE1,    // ASC_BREAKER
-    // 380-
-    StatusChange::NEGATIVE1,    // SN_SIGHT
-    StatusChange::NEGATIVE1,    // SN_FALCONASSAULT
-    StatusChange::NEGATIVE1,    // SN_SHARPSHOOTING
-    StatusChange::NEGATIVE1,    // SN_WINDWALK
-    StatusChange::NEGATIVE1,    // WS_MELTDOWN
-    StatusChange::NEGATIVE1,    // WS_CREATECOIN
-    StatusChange::NEGATIVE1,    // WS_CREATENUGGET
-    StatusChange::NEGATIVE1,    // WS_CARTBOOST
-    StatusChange::NEGATIVE1,    // WS_SYSTEMCREATE
-    StatusChange::NEGATIVE1,    // ST_CHASEWALK
-    // 390-
-    StatusChange::NEGATIVE1,    // ST_REJECTSWORD
-    StatusChange::NEGATIVE1,    // ST_STEALBACKPACK
-    StatusChange::NEGATIVE1,    // CR_ALCHEMY
-    StatusChange::NEGATIVE1,    // CR_SYNTHESISPOTION
-    StatusChange::NEGATIVE1,    // CG_ARROWVULCAN
-    StatusChange::NEGATIVE1,    // CG_MOONLIT
-    StatusChange::NEGATIVE1,    // CG_MARIONETTE
-    StatusChange::NEGATIVE1,    // LK_SPIRALPIERCE
-    StatusChange::NEGATIVE1,    // LK_HEADCRUSH
-    StatusChange::NEGATIVE1,    // LK_JOINTBEAT
-    // 400-
-    StatusChange::NEGATIVE1,    // HW_NAPALMVULCAN
-    StatusChange::NEGATIVE1,    // CH_SOULCOLLECT
-    StatusChange::NEGATIVE1,    // PF_MINDBREAKER
-    StatusChange::NEGATIVE1,    // PF_MEMORIZE
-    StatusChange::NEGATIVE1,    // PF_FOGWALL
-    StatusChange::NEGATIVE1,    // PF_SPIDERWEB
-    StatusChange::NEGATIVE1,    // ASC_METEORASSAULT
-    StatusChange::NEGATIVE1,    // ASC_CDP
-    StatusChange::NEGATIVE1,    // WE_BABY
-    StatusChange::NEGATIVE1,    // WE_CALLPARENT
-    // 410-
-    StatusChange::NEGATIVE1,    // WE_CALLBABY
-    StatusChange::NEGATIVE1,    // TK_RUN
-    StatusChange::NEGATIVE1,    // TK_READYSTORM
-    StatusChange::NEGATIVE1,    // TK_STORMKICK
-    StatusChange::NEGATIVE1,    // TK_READYDOWN
-    StatusChange::NEGATIVE1,    // TK_DOWNKICK
-    StatusChange::NEGATIVE1,    // TK_READYTURN
-    StatusChange::NEGATIVE1,    // TK_TURNKICK
-    StatusChange::NEGATIVE1,    // TK_READYCOUNTER
-    StatusChange::NEGATIVE1,    // TK_COUNTER
-}};
-
 struct skill_name_db skill_names[] =
 {
     {AC_OWL, "OWL", "Owl's_Eye"},
@@ -522,14 +50,6 @@ struct skill_name_db skill_names[] =
     {SkillID::ZERO, nullptr, nullptr}
 };
 
-static
-const int dirx[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
-static
-const int diry[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
-
-static
-int rdamage;
-
 earray<struct skill_db, SkillID, MAX_SKILL_DB> skill_db;
 
 
@@ -538,25 +58,11 @@ int skill_attack(BF attack_type, struct block_list *src,
         struct block_list *dsrc, struct block_list *bl,
         SkillID skillid, int skilllv, unsigned int tick, BCT flag);
 static
-int skill_delunitgroup(struct skill_unit_group *group);
-static
 void skill_devotion_end(struct map_session_data *md,
         struct map_session_data *sd, int target);
 static
-struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx,
-        int x, int y);
-static
-struct skill_unit_group *skill_initunitgroup(struct block_list *src,
-        int count, SkillID skillid, int skilllv, int unit_id);
-static
 void skill_status_change_timer(timer_id tid, tick_t tick,
         custom_id_t id, custom_data_t data);
-static
-int skill_unitgrouptickset_delete(struct block_list *bl, int group_id);
-static
-struct skill_unit_group_tickset *skill_unitgrouptickset_search(
-        struct block_list *bl, int group_id);
-
 
 int skill_get_hit(SkillID id)
 {
@@ -568,11 +74,6 @@ int skill_get_inf(SkillID id)
     return skill_db[id].inf;
 }
 
-int skill_get_pl(SkillID id)
-{
-    return skill_db[id].pl;
-}
-
 int skill_get_nk(SkillID id)
 {
     return skill_db[id].nk;
@@ -593,23 +94,11 @@ int skill_get_range(SkillID id, int lv)
     return (lv <= 0) ? 0 : skill_db[id].range[lv - 1];
 }
 
-static
-int skill_get_hp(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].hp[lv - 1];
-}
-
 int skill_get_sp(SkillID id, int lv)
 {
     return (lv <= 0) ? 0 : skill_db[id].sp[lv - 1];
 }
 
-static
-int skill_get_zeny(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].zeny[lv - 1];
-}
-
 int skill_get_num(SkillID id, int lv)
 {
     return (lv <= 0) ? 0 : skill_db[id].num[lv - 1];
@@ -625,26 +114,6 @@ int skill_get_delay(SkillID id, int lv)
     return (lv <= 0) ? 0 : skill_db[id].delay[lv - 1];
 }
 
-int skill_get_time(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].upkeep_time[lv - 1];
-}
-
-int skill_get_time2(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].upkeep_time2[lv - 1];
-}
-
-int skill_get_castdef(SkillID id)
-{
-    return skill_db[id].cast_def_rate;
-}
-
-int skill_get_weapontype(SkillID id)
-{
-    return skill_db[id].weapon;
-}
-
 int skill_get_inf2(SkillID id)
 {
     return skill_db[id].inf2;
@@ -655,42 +124,12 @@ int skill_get_maxcount(SkillID id)
     return skill_db[id].maxcount;
 }
 
-int skill_get_blewcount(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].blewcount[lv - 1];
-}
-
-static
-int skill_get_mhp(SkillID id, int lv)
-{
-    return (lv <= 0) ? 0 : skill_db[id].mhp[lv - 1];
-}
-
 static
 int skill_get_castnodex(SkillID id, int lv)
 {
     return (lv <= 0) ? 0 : skill_db[id].castnodex[lv - 1];
 }
 
-/* プロトタイプ */
-static
-struct skill_unit_group *skill_unitsetting(struct block_list *src,
-                                            SkillID skillid, int skilllv,
-                                            int x, int y, int flag);
-static
-int skill_check_condition(struct map_session_data *sd, int type);
-static
-void skill_status_change_timer_sub(struct block_list *bl,
-        struct block_list *src, StatusChange type, unsigned int tick);
-static
-void skill_landprotector(struct block_list *bl, SkillID skillid, int *alive);
-static
-void skill_trap_splash(struct block_list *bl,
-        struct block_list *src, int tick, int splash_count);
-static
-void skill_count_target(struct block_list *bl,
-        struct block_list *src, int *c);
-
 static
 int distance(int x0, int y0, int x1, int y1)
 {
@@ -706,7 +145,7 @@ int distance(int x0, int y0, int x1, int y1)
  *------------------------------------------
  */
 int skill_additional_effect(struct block_list *src, struct block_list *bl,
-                             SkillID skillid, int skilllv, BF attack_type,
+                             SkillID skillid, int skilllv, BF,
                              unsigned int)
 {
     struct map_session_data *sd = NULL;
@@ -715,7 +154,6 @@ int skill_additional_effect(struct block_list *src, struct block_list *bl,
     int luk;
 
     int sc_def_mdef, sc_def_vit, sc_def_int, sc_def_luk;
-    int sc_def_mdef2, sc_def_vit2, sc_def_int2, sc_def_luk2;
     int sc_def_phys_shield_spell;
 
     nullpo_ret(src);
@@ -726,11 +164,13 @@ int skill_additional_effect(struct block_list *src, struct block_list *bl,
 
     if (src->type == BL_PC)
     {
-        nullpo_ret(sd = (struct map_session_data *) src);
+        sd = (struct map_session_data *) src;
+        nullpo_ret(sd);
     }
     else if (src->type == BL_MOB)
     {
-        nullpo_ret(md = (struct mob_data *) src);  //未使用?
+        md = (struct mob_data *) src;
+        nullpo_ret(md);  //未使用?
     }
 
     sc_def_phys_shield_spell = 0;
@@ -746,10 +186,7 @@ int skill_additional_effect(struct block_list *src, struct block_list *bl,
     sc_def_luk = 100 - (3 + luk);
     //自分の耐性
     luk = battle_get_luk(src);
-    sc_def_mdef2 = 100 - (3 + battle_get_mdef(src) + luk / 3);
-    sc_def_vit2 = 100 - (3 + battle_get_vit(src) + luk / 3);
-    sc_def_int2 = 100 - (3 + battle_get_int(src) + luk / 3);
-    sc_def_luk2 = 100 - (3 + luk);
+
     if (bl->type == BL_MOB)
     {
         if (sc_def_mdef > 50)
@@ -779,206 +216,6 @@ int skill_additional_effect(struct block_list *src, struct block_list *bl,
             break;
     }
 
-    if (not (sd && bool(attack_type & BF_WEAPON)))
-        return 0;
-    earray<int, BadSC, BadSC::COUNT> arr_sc_def_card1 //=
-    {{
-        sc_def_mdef,    // stone
-        sc_def_mdef,    // freeze
-        sc_def_vit,     // stan
-        sc_def_int,     // sleep
-        sc_def_vit,     // poison
-        sc_def_luk,     // curse
-        sc_def_vit,     // silence
-        sc_def_int,     // confusion
-        sc_def_int,     // blind
-    }}, arr_sc_def_card2 //=
-    {{
-        sc_def_mdef2,   // stone
-        sc_def_mdef2,   // freeze
-        sc_def_vit2,    // stan
-        sc_def_int2,    // sleep
-        sc_def_vit2,    // poison
-        sc_def_luk2,    // curse
-        sc_def_vit2,    // silence
-        sc_def_int2,    // confusion
-        sc_def_int2,    // blind
-    }};
-
-    for (BadSC bi : erange(BadSC(), BadSC::COUNT))
-    {
-        StatusChange si = BadSC_to_SC(bi);
-        int sc_def_card1 = arr_sc_def_card1[bi];
-        int eff1 = sd->addeff[bi];
-        if (sd->state.arrow_atk)
-            eff1 += sd->arrow_addeff[bi];
-        if (MRAND(10000) < eff1 * sc_def_card1 / 100)
-        {
-            if (battle_config.battle_log)
-                PRINTF("PC %d skill_addeff: cardによる異常発動 %d %d\n",
-                     sd->bl.id, si, eff1);
-
-            skill_status_change_start(bl, si, 7, 0, 0, 0,
-                                    (bi == BadSC::CONFUSION)
-                                    ? 10000 + 7000
-                                    : 0,
-                                    0);
-        }
-
-        int sc_def_card2 = arr_sc_def_card2[bi];
-        int eff2 = sd->addeff2[bi];
-
-        if (MRAND(10000) < eff2 * sc_def_card2 / 100)
-        {
-            if (battle_config.battle_log)
-                PRINTF("PC %d skill_addeff: cardによる異常発動 %d %d\n",
-                     src->id, si, eff2);
-            skill_status_change_start(src, si, 7, 0, 0, 0,
-                                   (bi == BadSC::CONFUSION)
-                                   ? 10000 + 7000
-                                   : 0,
-                                   0);
-        }
-    }
-    return 0;
-}
-
-/*=========================================================================
- スキル攻撃吹き飛ばし処理
--------------------------------------------------------------------------*/
-static
-int skill_blown(struct block_list *src, struct block_list *target, int count)
-{
-    int dx = 0, dy = 0, nx, ny;
-    int x = target->x, y = target->y;
-    int ret;
-    MS prev_state = MS_IDLE;
-    int moveblock;
-    struct map_session_data *sd = NULL;
-    struct mob_data *md = NULL;
-    struct skill_unit *su = NULL;
-
-    nullpo_ret(src);
-    nullpo_ret(target);
-
-    if (target->type == BL_PC)
-    {
-        nullpo_ret(sd = (struct map_session_data *) target);
-    }
-    else if (target->type == BL_MOB)
-    {
-        nullpo_ret(md = (struct mob_data *) target);
-    }
-    else if (target->type == BL_SKILL)
-    {
-        nullpo_ret(su = (struct skill_unit *) target);
-    }
-    else
-        return 0;
-
-    if (!(count & 0x10000 && (sd || md || su)))
-    {                           /* 指定なしなら位置関係から方向を求める */
-        dx = target->x - src->x;
-        dx = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0);
-        dy = target->y - src->y;
-        dy = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0);
-    }
-    if (dx == 0 && dy == 0)
-    {
-        int dir = battle_get_dir(target);
-        if (dir >= 0 && dir < 8)
-        {
-            dx = -dirx[dir];
-            dy = -diry[dir];
-        }
-    }
-
-    ret = path_blownpos(target->m, x, y, dx, dy, count & 0xffff);
-    nx = ret >> 16;
-    ny = ret & 0xffff;
-    moveblock = (x / BLOCK_SIZE != nx / BLOCK_SIZE
-                 || y / BLOCK_SIZE != ny / BLOCK_SIZE);
-
-    if (count & 0x20000)
-    {
-        battle_stopwalking(target, 1);
-        if (sd)
-        {
-            sd->to_x = nx;
-            sd->to_y = ny;
-            sd->walktimer = 1;
-            clif_walkok(sd);
-            clif_movechar(sd);
-        }
-        else if (md)
-        {
-            md->to_x = nx;
-            md->to_y = ny;
-            prev_state = md->state.state;
-            md->state.state = MS_WALK;
-            clif_fixmobpos(md);
-        }
-    }
-    else
-        battle_stopwalking(target, 2);
-
-    dx = nx - x;
-    dy = ny - y;
-
-    if (sd)                     /* 画面外に出たので消去 */
-        map_foreachinmovearea(std::bind(clif_pcoutsight, ph::_1, sd),
-                target->m, x - AREA_SIZE, y - AREA_SIZE,
-                x + AREA_SIZE, y + AREA_SIZE,
-                dx, dy, BL_NUL);
-    else if (md)
-        map_foreachinmovearea(std::bind(clif_moboutsight, ph::_1, md),
-                target->m, x - AREA_SIZE, y - AREA_SIZE,
-                x + AREA_SIZE, y + AREA_SIZE,
-                dx, dy, BL_PC);
-
-    if (su)
-    {
-        skill_unit_move_unit_group(su->group, target->m, dx, dy);
-    }
-    else
-    {
-//      eptr<struct status_change, StatusChange> sc_data=battle_get_sc_data(target);
-        if (moveblock)
-            map_delblock(target);
-        target->x = nx;
-        target->y = ny;
-        if (moveblock)
-            map_addblock(target);
-/*ダンス中にエフェクトは移動しないらしい
-                if (sc_data && sc_data[SC_DANCING].timer!=-1){ //対象がダンス中なのでエフェクトも移動
-                        struct skill_unit_group *sg= (struct skill_unit_group *)sc_data[SC_DANCING].val2;
-                        if (sg)
-                                skill_unit_move_unit_group(sg,target->m,dx,dy);
-                }
-*/
-    }
-
-    if (sd)
-    {                           /* 画面内に入ってきたので表示 */
-        map_foreachinmovearea(std::bind(clif_pcinsight, ph::_1, sd),
-                target->m, nx - AREA_SIZE, ny - AREA_SIZE,
-                nx + AREA_SIZE, ny + AREA_SIZE,
-                -dx, -dy, BL_NUL);
-        if (count & 0x20000)
-            sd->walktimer = -1;
-    }
-    else if (md)
-    {
-        map_foreachinmovearea(std::bind(clif_mobinsight, ph::_1, md),
-                target->m, nx - AREA_SIZE, ny - AREA_SIZE,
-                nx + AREA_SIZE, ny + AREA_SIZE,
-                -dx, -dy, BL_PC);
-        if (count & 0x20000)
-            md->state.state = prev_state;
-    }
-
-    skill_unit_move(target, gettick(), (count & 0xffff) + 7); /* スキルユニットの判定 */
-
     return 0;
 }
 
@@ -1002,7 +239,6 @@ int skill_attack(BF attack_type, struct block_list *src,
     eptr<struct status_change, StatusChange> sc_data;
     int type, lv, damage;
 
-    rdamage = 0;
     nullpo_ret(src);
     nullpo_ret(dsrc);
     nullpo_ret(bl);
@@ -1020,11 +256,6 @@ int skill_attack(BF attack_type, struct block_list *src,
         return 0;
     if (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl))    //対象がPCですでに死んでいたら何もしない
         return 0;
-    if (sc_data && sc_data[SC_HIDING].timer != -1)
-    {                           //ハイディング状態で
-        if (skill_get_pl(skillid) != 2)    //スキルの属性が地属性でなければ何もしない
-            return 0;
-    }
     if (src->type == BL_PC && ((struct map_session_data *) src)->chatID)    //術者がPCでチャット中なら何もしない
         return 0;
     if (dsrc->type == BL_PC && ((struct map_session_data *) dsrc)->chatID)  //術者がPCでチャット中なら何もしない
@@ -1033,76 +264,16 @@ int skill_attack(BF attack_type, struct block_list *src,
 //何もしない判定ここまで
 
     type = -1;
-    lv = (flag >> 20) & 0xf;
-    dmg = battle_calc_attack(attack_type, src, bl, skillid, skilllv, flag & 0xff); //ダメージ計算
+    lv = flag.level;
+    dmg = battle_calc_attack(attack_type, src, bl, skillid, skilllv, flag.lo); //ダメージ計算
 
     damage = dmg.damage + dmg.damage2;
 
     if (lv == 15)
         lv = -1;
 
-    if (flag & 0xff00)
-        type = (flag & 0xff00) >> 8;
-
-    if (damage <= 0 || damage < dmg.div_)   //吹き飛ばし判定?※
-        dmg.blewcount = 0;
-
-//武器スキル?ここから
-    //AppleGirl Was Here
-    if (bool(attack_type & BF_MAGIC)
-        && damage > 0
-        && src != bl
-        && src == dsrc)
-    {                           //Blah Blah
-        if (bl->type == BL_PC)
-        {                       //Blah Blah
-            struct map_session_data *tsd = (struct map_session_data *) bl;
-            if (tsd->magic_damage_return > 0)
-            {                   //More Blah
-                rdamage += damage * tsd->magic_damage_return / 100;
-                if (rdamage < 1)
-                    rdamage = 1;
-            }
-        }
-    }
-    //Stop Here
-    if (bool(attack_type & BF_WEAPON)
-        && damage > 0
-        && src != bl
-        && src == dsrc)
-    {                           //武器スキル&ダメージあり&使用者と対象者が違う&src=dsrc
-        if (bool(dmg.flag & BF_SHORT))
-        {                       //近距離攻撃時?※
-            if (bl->type == BL_PC)
-            {                   //対象がPCの時
-                struct map_session_data *tsd = (struct map_session_data *) bl;
-                nullpo_ret(tsd);
-                if (tsd->short_weapon_damage_return > 0)
-                {               //近距離攻撃跳ね返し?※
-                    rdamage += damage * tsd->short_weapon_damage_return / 100;
-                    if (rdamage < 1)
-                        rdamage = 1;
-                }
-            }
-        }
-        else if (bool(dmg.flag & BF_LONG))
-        {                       //遠距離攻撃時?※
-            if (bl->type == BL_PC)
-            {                   //対象がPCの時
-                struct map_session_data *tsd = (struct map_session_data *) bl;
-                nullpo_ret(tsd);
-                if (tsd->long_weapon_damage_return > 0)
-                {               //遠距離攻撃跳ね返し?※
-                    rdamage += damage * tsd->long_weapon_damage_return / 100;
-                    if (rdamage < 1)
-                        rdamage = 1;
-                }
-            }
-        }
-        if (rdamage > 0)
-            clif_damage(src, src, tick, dmg.amotion, 0, rdamage, 1, 4, 0);
-    }
-//武器スキル?ここまで
+    if (flag.mid)
+        type = flag.mid;
 
     switch (skillid)
     {
@@ -1114,14 +285,6 @@ int skill_attack(BF attack_type, struct block_list *src,
                                (lv != 0) ? lv : skilllv,
                                (skillid == SkillID::ZERO) ? 5 : type);
     }
-    if (dmg.blewcount > 0)
-    {                           /* 吹き飛ばし処理とそのパケット */
-        skill_blown(dsrc, bl, dmg.blewcount);
-        if (bl->type == BL_MOB)
-            clif_fixmobpos((struct mob_data *) bl);
-        else
-            clif_fixpos(bl);
-    }
 
     map_freeblock_lock();
     /* 実際にダメージ処理を行う */
@@ -1147,11 +310,11 @@ int skill_attack(BF attack_type, struct block_list *src,
                     target = md->target_id;
                     if (src->type == BL_PC)
                         md->target_id = src->id;
-                    mobskill_use(md, tick, MSC_SKILLUSED, skillid);
+                    mobskill_use(md, tick, MobSkillCondition::ANY, skillid);
                     md->target_id = target;
                 }
                 else
-                    mobskill_use(md, tick, MSC_SKILLUSED, skillid);
+                    mobskill_use(md, tick, MobSkillCondition::ANY, skillid);
             }
         }
     }
@@ -1189,9 +352,6 @@ int skill_attack(BF attack_type, struct block_list *src,
             pc_heal(sd, hp, sp);
     }
 
-    if (rdamage > 0)
-        battle_damage(bl, src, rdamage, 0);
-
     map_freeblock_unlock();
 
     return (dmg.damage + dmg.damage2);  /* 与ダメを返す */
@@ -1208,143 +368,13 @@ void skill_area_sub(struct block_list *bl,
 {
     nullpo_retv(bl);
 
-    if (bl->type != BL_PC && bl->type != BL_MOB && bl->type != BL_SKILL)
+    if (bl->type != BL_PC && bl->type != BL_MOB)
         return;
 
     if (battle_check_target(src, bl, flag) > 0)
         func(src, bl, skill_id, skill_lv, tick, flag);
 }
 
-int skill_check_unit_range(int, int, int, int, SkillID)
-{
-    return 0;
-}
-
-static
-void skill_check_unit_range2_sub(struct block_list *bl, int *c)
-{
-    nullpo_retv(bl);
-    nullpo_retv(c);
-
-    if (bl->prev == NULL || (bl->type != BL_PC && bl->type != BL_MOB))
-        return;
-
-    if (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl))
-        return;
-
-    (*c)++;
-}
-
-int skill_check_unit_range2(int m, int x, int y, int range)
-{
-    int c = 0;
-
-    map_foreachinarea(std::bind(skill_check_unit_range2_sub, ph::_1, &c),
-            m, x - range, y - range,
-            x + range, y + range, BL_NUL);
-
-    return c;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static
-void skill_timer(timer_id, tick_t tick, custom_id_t id, custom_data_t data)
-{
-    struct map_session_data *sd = NULL;
-    struct mob_data *md = NULL;
-    struct block_list *src = map_id2bl(id), *target;
-    struct skill_timerskill *skl = NULL;
-
-    nullpo_retv(src);
-
-    if (src->prev == NULL)
-        return;
-
-    if (src->type == BL_PC)
-    {
-        nullpo_retv(sd = (struct map_session_data *) src);
-        skl = &sd->skilltimerskill[data];
-    }
-    else if (src->type == BL_MOB)
-    {
-        nullpo_retv(md = (struct mob_data *) src);
-        skl = &md->skilltimerskill[data];
-    }
-
-    else
-        return;
-
-    nullpo_retv(skl);
-
-    skl->timer = -1;
-    if (skl->target_id)
-    {
-        target = map_id2bl(skl->target_id);
-        if (target == NULL)
-            return;
-        if (target->prev == NULL)
-            return;
-        if (src->m != target->m)
-            return;
-        if (sd && pc_isdead(sd))
-            return;
-        if (target->type == BL_PC
-            && pc_isdead((struct map_session_data *) target))
-            return;
-
-        switch (skl->skill_id)
-        {
-            default:
-                skill_attack(skl->type.bf, src, src, target, skl->skill_id,
-                              skl->skill_lv, tick, skl->flag);
-                break;
-        }
-    }
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-int skill_cleartimerskill(struct block_list *src)
-{
-    int i;
-
-    nullpo_ret(src);
-
-    if (src->type == BL_PC)
-    {
-        struct map_session_data *sd = (struct map_session_data *) src;
-        nullpo_ret(sd);
-        for (i = 0; i < MAX_SKILLTIMERSKILL; i++)
-        {
-            if (sd->skilltimerskill[i].timer != -1)
-            {
-                delete_timer(sd->skilltimerskill[i].timer, skill_timer);
-                sd->skilltimerskill[i].timer = -1;
-            }
-        }
-    }
-    else if (src->type == BL_MOB)
-    {
-        struct mob_data *md = (struct mob_data *) src;
-        nullpo_ret(md);
-        for (i = 0; i < MAX_MOBSKILLTIMERSKILL; i++)
-        {
-            if (md->skilltimerskill[i].timer != -1)
-            {
-                delete_timer(md->skilltimerskill[i].timer, skill_timer);
-                md->skilltimerskill[i].timer = -1;
-            }
-        }
-    }
-
-    return 0;
-}
-
 /* 範囲スキル使用処理小分けここまで
  * -------------------------------------------------------------------------
  */
@@ -1386,7 +416,7 @@ int skill_castend_damage_id(struct block_list *src, struct block_list *bl,
             break;
 
         case NPC_SELFDESTRUCTION:  /* 自爆 */
-            if (flag & 1)
+            if (flag.lo & 1)
             {
                 /* 個別にダメージを与える */
                 if (src->type == BL_MOB)
@@ -1420,7 +450,7 @@ int skill_castend_damage_id(struct block_list *src, struct block_list *bl,
         case SkillID::ZERO:
             if (sd)
             {
-                if (flag & 3)
+                if (flag.lo & 3)
                 {
                     if (bl->id != skill_area_temp_id)
                         skill_attack(BF_WEAPON, src, src, bl, skillid,
@@ -1428,11 +458,11 @@ int skill_castend_damage_id(struct block_list *src, struct block_list *bl,
                 }
                 else
                 {
-                    int ar = sd->splash_range;
+                    // TODO does this happen?
                     skill_area_temp_id = bl->id;
                     map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
-                            bl->m, bl->x - ar, bl->y - ar,
-                            bl->x + ar, bl->y + ar, BL_NUL);
+                            bl->m, bl->x - 0, bl->y - 0,
+                            bl->x + 0, bl->y + 0, BL_NUL);
                 }
             }
             break;
@@ -1450,6 +480,8 @@ int skill_castend_damage_id(struct block_list *src, struct block_list *bl,
  * スキル使用(詠唱完了、ID指定支援系)
  *------------------------------------------
  */
+// skillid.nk == 1
+// so skillid in (NPC_SUMMONSLAVE, NPC_EMOTION)
 int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl,
         SkillID skillid, int skilllv,
         unsigned int, BCT)
@@ -1475,11 +507,13 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl,
 
     if (bl->type == BL_PC)
     {
-        nullpo_retr(1, dstsd = (struct map_session_data *) bl);
+        dstsd = (struct map_session_data *) bl;
+        nullpo_retr(1, dstsd);
     }
     else if (bl->type == BL_MOB)
     {
-        nullpo_retr(1, dstmd = (struct mob_data *) bl);
+        dstmd = (struct mob_data *) bl;
+        nullpo_retr(1, dstmd);
         if (sc_def_vit > 50)
             sc_def_vit = 50;
         if (sc_def_mdef > 50)
@@ -1502,32 +536,21 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl,
     map_freeblock_lock();
     switch (skillid)
     {
-        case NPC_SELFDESTRUCTION:  /* 自爆 */
-            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
-                                       skilllv, uint16_t(skillid), 0, 0,
-                                       skill_get_time(skillid, skilllv), 0);
-            break;
-
-        case NPC_SUMMONSLAVE:  /* 手下召喚 */
+        case NPC_SUMMONSLAVE:
             if (md && !md->master_id)
             {
                 mob_summonslave(md,
-                                 mob_db[md->mob_class].skill[md->skillidx].val,
-                                 skilllv,
-                                 (true) ? 1 : 0);
+                        mob_db[md->mob_class].skill[md->skillidx].val,
+                        skilllv,
+                        (true) ? 1 : 0);
             }
             break;
 
-        case NPC_EMOTION:      /* エモーション */
+        case NPC_EMOTION:
             if (md)
                 clif_emotion(&md->bl,
-                              mob_db[md->mob_class].skill[md->skillidx].val[0]);
+                        mob_db[md->mob_class].skill[md->skillidx].val[0]);
             break;
-
-        default:
-            PRINTF("Unknown skill used:%d\n", skillid);
-            map_freeblock_unlock();
-            return 1;
     }
 
     map_freeblock_unlock();
@@ -1535,3264 +558,986 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl,
 }
 
 /*==========================================
- * スキル使用(詠唱完了、ID指定)
+ * 詠唱時間計算
  *------------------------------------------
  */
-static
-void skill_castend_id(timer_id tid, tick_t tick, custom_id_t id, custom_data_t)
+int skill_castfix(struct block_list *bl, int time)
 {
-    struct map_session_data *sd = map_id2sd(id) /*,*target_sd=NULL */ ;
-    struct block_list *bl;
-    int range, inf2;
-
-    nullpo_retv( sd);
-
-    if (sd->bl.prev == NULL)    //prevが無いのはありなの?
-        return;
+    struct mob_data *md;        // [Valaris]
+    eptr<struct status_change, StatusChange> sc_data;
+    int dex;
+    int castrate = 100;
+    SkillID skill;
+    int lv, castnodex;
 
-    if (sd->skilltimer != tid)  /* タイマIDの確認 */
-        return;
-    sd->skilltimer = -1;
+    nullpo_ret(bl);
 
-    if ((bl = map_id2bl(sd->skilltarget)) == NULL || bl->prev == NULL)
-    {
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return;
-    }
-    if (sd->bl.m != bl->m || pc_isdead(sd))
-    {                           //マップが違うか自分が死んでいる
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return;
+    if (bl->type == BL_MOB)
+    {                           // Crash fix [Valaris]
+        md = (struct mob_data *) bl;
+        skill = md->skillid;
+        lv = md->skilllv;
     }
-
-    inf2 = skill_get_inf2(sd->skillid);
-    if (((skill_get_inf(sd->skillid) & 1) || inf2 & 4) &&  // 彼我敵対関係チェック
-        battle_check_target(&sd->bl, bl, BCT_ENEMY) <= 0)
+    else
     {
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return;
-    }
-    if (inf2 & 0xC00 && sd->bl.id != bl->id)
-    {
-        int fail_flag = 1;
-        if (inf2 & 0x400 && battle_check_target(&sd->bl, bl, BCT_PARTY) > 0)
-            fail_flag = 0;
-        if (fail_flag)
-        {
-            clif_skill_fail(sd, sd->skillid, 0, 0);
-            sd->canact_tick = tick;
-            sd->canmove_tick = tick;
-            sd->skillitem = SkillID::NEGATIVE;
-            sd->skillitemlv = -1;
-            return;
-        }
+        skill = SkillID::ZERO;
+        lv = 0;
     }
 
-    range = skill_get_range(sd->skillid, sd->skilllv);
-    if (range < 0)
-        range = battle_get_range(&sd->bl) - (range + 1);
-    range += battle_config.pc_skill_add_range;
-    if (battle_config.skill_out_range_consume)
-    {
-        // changed to allow casting when target walks out of range [Valaris]
-        if (range < distance(sd->bl.x, sd->bl.y, bl->x, bl->y))
-        {
-            clif_skill_fail(sd, sd->skillid, 0, 0);
-            sd->canact_tick = tick;
-            sd->canmove_tick = tick;
-            sd->skillitem = SkillID::NEGATIVE;
-            sd->skillitemlv = -1;
-            return;
-        }
-    }
-    if (!skill_check_condition(sd, 1))
-    {                           /* 使用条件チェック */
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return;
-    }
-    sd->skillitem = SkillID::NEGATIVE;
-    sd->skillitemlv = -1;
-    if (battle_config.skill_out_range_consume)
-    {
-        if (range < distance(sd->bl.x, sd->bl.y, bl->x, bl->y))
-        {
-            clif_skill_fail(sd, sd->skillid, 0, 0);
-            sd->canact_tick = tick;
-            sd->canmove_tick = tick;
-            return;
-        }
-    }
+    sc_data = battle_get_sc_data(bl);
+    dex = battle_get_dex(bl);
+
+    if (skill > MAX_SKILL_DB /*|| skill < SkillID()*/)
+        return 0;
 
-    if (battle_config.pc_skill_log)
-        PRINTF("PC %d skill castend skill=%d\n",
-                sd->bl.id, sd->skillid);
-    pc_stop_walking(sd, 0);
+    castnodex = skill_get_castnodex(skill, lv);
 
-    switch (skill_get_nk(sd->skillid))
+    if (time == 0)
+        return 0;
+    if (castnodex > 0 && bl->type == BL_PC)
+        castrate = 100;
+    else if (castnodex <= 0 && bl->type == BL_PC)
     {
-            /* 攻撃系/吹き飛ばし系 */
-        case 0:
-        case 2:
-            skill_castend_damage_id(&sd->bl, bl,
-                    sd->skillid, sd->skilllv,
-                    tick, BCT_ZERO);
-            break;
-        case 1:                /* 支援系 */
-            skill_castend_nodamage_id(&sd->bl, bl,
-                    sd->skillid, sd->skilllv,
-                    tick, BCT_ZERO);
-            break;
+        castrate = 100;
+        time =
+            time * castrate * (battle_config.castrate_dex_scale -
+                               dex) / (battle_config.castrate_dex_scale *
+                                       100);
+        time = time * battle_config.cast_rate / 100;
     }
+
+    return (time > 0) ? time : 0;
 }
 
 /*==========================================
- * スキル使用(詠唱完了、map指定)
+ * ディレイ計算
  *------------------------------------------
  */
-int skill_castend_map(struct map_session_data *sd, SkillID skill_num,
-                       const char *mapname)
+int skill_delayfix(struct block_list *bl, int time)
 {
-    nullpo_ret(sd);
-    if (sd->bl.prev == NULL || pc_isdead(sd))
-        return 0;
+    eptr<struct status_change, StatusChange> sc_data;
 
-    if (bool(sd->opt1)
-        || bool(sd->status.option & Option::HIDE2))
-        return 0;
+    nullpo_ret(bl);
 
-    if (skill_num != sd->skillid)   /* 不正パケットらしい */
+    sc_data = battle_get_sc_data(bl);
+    if (time <= 0)
         return 0;
 
-    pc_stopattack(sd);
-
-    if (battle_config.pc_skill_log)
-        PRINTF("PC %d skill castend skill =%d map=%s\n",
-                sd->bl.id, skill_num, mapname);
-    pc_stop_walking(sd, 0);
-
-    if (strcmp(mapname, "cancel") == 0)
-        return 0;
+    if (bl->type == BL_PC)
+    {
+        if (battle_config.delay_dependon_dex)   /* dexの影響を計算する */
+            time =
+                time * (battle_config.castrate_dex_scale -
+                        battle_get_dex(bl)) /
+                battle_config.castrate_dex_scale;
+        time = time * battle_config.delay_rate / 100;
+    }
 
-    return 0;
+    return (time > 0) ? time : 0;
 }
 
 /*==========================================
- * スキルユニット設定処理
+ * スキル詠唱キャンセル
  *------------------------------------------
  */
-struct skill_unit_group *skill_unitsetting(struct block_list *src,
-        SkillID skillid, int skilllv,
-        int x, int y, int)
+int skill_castcancel(struct block_list *bl, int)
 {
-    struct skill_unit_group *group;
-    int i, count = 1, limit_ = 10000, val1_ = 0, val2_ = 0;
-    BCT target = BCT_ENEMY;
-    int interval = 1000, range_ = 0;
+    int inf;
 
-    nullpo_ret(src);
+    nullpo_ret(bl);
+
+    if (bl->type == BL_PC)
+    {
+        struct map_session_data *sd = (struct map_session_data *) bl;
+        unsigned long tick = gettick();
+        nullpo_ret(sd);
+        sd->canact_tick = tick;
+        sd->canmove_tick = tick;
 
-    nullpo_retr(NULL, group = skill_initunitgroup(src, count, skillid, skilllv, 0));
-    group->limit = limit_;
-    group->val1 = val1_;
-    group->val2 = val2_;
-    group->target_flag = target;
-    group->interval = interval;
-    group->range = range_;
-    for (i = 0; i < count; i++)
+        return 0;
+    }
+    else if (bl->type == BL_MOB)
     {
-        struct skill_unit *unit;
-        int ux = x, uy = y, val1 = skilllv, val2 = 0, limit =
-            group->limit, alive = 1;
-        int range = group->range;
-        //直上スキルの場合設置座標上にランドプロテクターがないかチェック
-        if (range <= 0)
-            map_foreachinarea(std::bind(skill_landprotector, ph::_1, skillid, &alive),
-                    src->m, ux, uy,
-                    ux, uy, BL_SKILL);
-
-        if (alive)
+        struct mob_data *md = (struct mob_data *) bl;
+        nullpo_ret(md);
+        if (md->skilltimer != -1)
         {
-            nullpo_retr(NULL, unit = skill_initunit(group, i, ux, uy));
-            unit->val1 = val1;
-            unit->val2 = val2;
-            unit->limit = limit;
-            unit->range = range;
+            if ((inf = skill_get_inf(md->skillid)) == 2 || inf == 32)
+                delete_timer(md->skilltimer, mobskill_castend_pos);
+            else
+                delete_timer(md->skilltimer, mobskill_castend_id);
+            md->skilltimer = -1;
+            clif_skillcastcancel(bl);
         }
+        return 0;
     }
-    return group;
+    return 1;
 }
 
 /*==========================================
- * スキルユニットの発動イベント
+ * ディボーション 有効確認
  *------------------------------------------
  */
-static
-int skill_unit_onplace(struct skill_unit *src, struct block_list *bl,
-                        unsigned int tick)
+void skill_devotion(struct map_session_data *md, int)
 {
-    struct skill_unit_group *sg;
-    struct block_list *ss;
-    struct skill_unit_group_tickset *ts;
-    struct map_session_data *srcsd = NULL;
-    int diff, goflag, splash_count = 0;
-
-    nullpo_ret(src);
-    nullpo_ret(bl);
-
-    if (bl->prev == NULL || !src->alive
-        || (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl)))
-        return 0;
-
-    nullpo_ret(sg = src->group);
-    nullpo_ret(ss = map_id2bl(sg->src_id));
-
-    if (ss->type == BL_PC)
-        nullpo_ret(srcsd = (struct map_session_data *) ss);
-    if (srcsd && srcsd->chatID)
-        return 0;
-
-    if (bl->type != BL_PC && bl->type != BL_MOB)
-        return 0;
-    nullpo_ret(ts = skill_unitgrouptickset_search(bl, sg->group_id));
-    diff = DIFF_TICK(tick, ts->tick);
-    goflag = (diff > sg->interval || diff < 0);
-
-    //対象がLP上に居る場合は無効
-    map_foreachinarea(std::bind(skill_landprotector, ph::_1, SkillID::ZERO, &goflag),
-            bl->m, bl->x, bl->y,
-            bl->x, bl->y, BL_SKILL);
+    // 総確認
+    int n;
 
-    if (!goflag)
-        return 0;
-    ts->tick = tick;
-    ts->group_id = sg->group_id;
+    nullpo_retv(md);
 
-    switch (sg->unit_id)
+    for (n = 0; n < 5; n++)
     {
-        case 0x83:             /* サンクチュアリ */
-        {
-            int race = battle_get_race(bl);
-            int damage_flag =
-                (battle_check_undead(race, battle_get_elem_type(bl))
-                 || race == 6) ? 1 : 0;
-
-            if (battle_get_hp(bl) >= battle_get_max_hp(bl) && !damage_flag)
-                break;
-
-            if ((sg->val1--) <= 0)
-            {
-                skill_delunitgroup(sg);
-                return 0;
-            }
-            if (!damage_flag)
-            {
-                int heal = sg->val2;
-                if (bl->type == BL_PC
-                    && ((struct map_session_data *) bl)->
-                    special_state.no_magic_damage)
-                    heal = 0;   /* 黄金蟲カード(ヒール量0) */
-                battle_heal(NULL, bl, heal, 0, 0);
-            }
-            else
-                skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
-                              sg->skill_lv, tick, BCT_ZERO);
-        }
-            break;
-
-        case 0x84:             /* マグヌスエクソシズム */
-        {
-            int race = battle_get_race(bl);
-            int damage_flag =
-                (battle_check_undead(race, battle_get_elem_type(bl))
-                 || race == 6) ? 1 : 0;
-
-            if (!damage_flag)
-                return 0;
-            skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
-                          sg->skill_lv, tick, BCT_ZERO);
-        }
-            break;
-
-        case 0x85:             /* ニューマ */
-        {
-            struct skill_unit *unit2;
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            if (sc_data && sc_data[SC_PNEUMA].timer == -1)
-                skill_status_change_start(bl, SC_PNEUMA, sg->skill_lv,
-                        (int) src, 0, 0, 0, 0);
-            else if ((unit2 = (struct skill_unit *) sc_data[SC_PNEUMA].val2)
-                     && unit2 != src)
-            {
-                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
-                    skill_status_change_start(bl, SC_PNEUMA, sg->skill_lv,
-                                               (int) src, 0, 0, 0, 0);
-                ts->tick -= sg->interval;
-            }
-        }
-            break;
-        case 0x7e:             /* セイフティウォール */
+        if (md->dev.val1[n])
         {
-            struct skill_unit *unit2;
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            if (sc_data && sc_data[SC_SAFETYWALL].timer == -1)
-                skill_status_change_start(bl, SC_SAFETYWALL, sg->skill_lv,
-                        (int) src, 0, 0, 0, 0);
-            else if ((unit2 = (struct skill_unit *) sc_data[SC_SAFETYWALL].val2)
-                     && unit2 != src)
+            struct map_session_data *sd = map_id2sd(md->dev.val1[n]);
+            // 相手が見つからない // 相手をディボしてるのが自分じゃない // 距離が離れてる
+            if (sd == NULL
+                || (md->bl.id != 0/* was something else - TODO remove this */)
+                || skill_devotion3(&md->bl, md->dev.val1[n]))
             {
-                if (sg->val1 < unit2->group->val1)
-                    skill_status_change_start(bl, SC_SAFETYWALL, sg->skill_lv,
-                                               (int) src, 0, 0, 0, 0);
-                ts->tick -= sg->interval;
+                skill_devotion_end(md, sd, n);
             }
         }
-            break;
-
-        case 0x86:             /* ロードオブヴァーミリオン(&ストームガスト &グランドクロス) */
-            skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
-                          sg->skill_lv, tick, BCT_ZERO);
-            break;
-
-        case 0x7f:             /* ファイヤーウォール */
-            if ((src->val2--) > 0)
-                skill_attack(BF_MAGIC, ss, &src->bl, bl,
-                              sg->skill_id, sg->skill_lv, tick, BCT_ZERO);
-            if (src->val2 <= 0)
-                skill_delunit(src);
-            break;
-
-        case 0x87:             /* ファイアーピラー(発動前) */
-            skill_delunit(src);
-            skill_unitsetting(ss, sg->skill_id, sg->skill_lv, src->bl.x,
-                               src->bl.y, 1);
-            break;
-
-        case 0x88:             /* ファイアーピラー(発動後) */
-            if (DIFF_TICK(tick, sg->tick) < 150)
-                skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
-                              sg->skill_lv, tick, BCT_ZERO);
-            break;
-
-        case 0x90:             /* スキッドトラップ */
-        {
-            int i, c = skill_get_blewcount(sg->skill_id, sg->skill_lv);
-            for (i = 0; i < c; i++)
-                skill_blown(&src->bl, bl, 1 | 0x30000);
-            sg->unit_id = 0x8c;
-            clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
-        }
-            break;
-
-        case 0x93:             /* ランドマイン */
-            skill_attack(BF_MISC, ss, &src->bl, bl, sg->skill_id,
-                          sg->skill_lv, tick, BCT_ZERO);
-            sg->unit_id = 0x8c;
-            clif_changelook(&src->bl, LOOK_BASE, 0x88);
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
-            break;
-
-        case 0x8f:             /* ブラストマイン */
-        case 0x94:             /* ショックウェーブトラップ */
-        case 0x95:             /* サンドマン */
-        case 0x96:             /* フラッシャー */
-        case 0x97:             /* フリージングトラップ */
-        case 0x98:             /* クレイモアートラップ */
-            map_foreachinarea(std::bind(skill_count_target, ph::_1,  &src->bl, &splash_count),
-                    src->bl.m, src->bl.x - src->range, src->bl.y - src->range,
-                    src->bl.x + src->range, src->bl.y + src->range, BL_NUL);
-            map_foreachinarea(std::bind(skill_trap_splash, ph::_1, &src->bl, tick, splash_count),
-                    src->bl.m, src->bl.x - src->range, src->bl.y - src->range,
-                    src->bl.x + src->range, src->bl.y + src->range, BL_NUL);
-            sg->unit_id = 0x8c;
-            clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
-            break;
+    }
+}
 
-        case 0x91:             /* アンクルスネア */
-        {
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            if (sg->val2 == 0 && sc_data && sc_data[SC_ANKLE].timer == -1)
-            {
-                int moveblock = (bl->x / BLOCK_SIZE != src->bl.x / BLOCK_SIZE
-                                  || bl->y / BLOCK_SIZE !=
-                                  src->bl.y / BLOCK_SIZE);
-                int sec = skill_get_time2(sg->skill_id,
-                                            sg->skill_lv) -
-                    (double) battle_get_agi(bl) * 0.1;
-                if (bool(battle_get_mode(bl) & MobMode::BOSS))
-                    sec = sec / 5;
-                battle_stopwalking(bl, 1);
-                skill_status_change_start(bl, SC_ANKLE,
-                        sg->skill_lv, 0, 0, 0,
-                        sec, 0);
-
-                if (moveblock)
-                    map_delblock(bl);
-                bl->x = src->bl.x;
-                bl->y = src->bl.y;
-                if (moveblock)
-                    map_addblock(bl);
-                if (bl->type == BL_MOB)
-                    clif_fixmobpos((struct mob_data *) bl);
-                else
-                    clif_fixpos(bl);
-                sg->limit = DIFF_TICK(tick, sg->tick) + sec;
-                sg->val2 = bl->id;
-            }
-        }
-            break;
+int skill_devotion3(struct block_list *bl, int target)
+{
+    // クルセが歩いた時の距離チェック
+    struct map_session_data *md;
+    struct map_session_data *sd;
+    int n, r = 0;
 
-        case 0x80:             /* ワープポータル(発動後) */
-            if (bl->type == BL_PC)
-            {
-                struct map_session_data *sd = (struct map_session_data *) bl;
-                if (sd && src->bl.m == bl->m && src->bl.x == bl->x
-                    && src->bl.y == bl->y && src->bl.x == sd->to_x
-                    && src->bl.y == sd->to_y)
-                {
-                    if (battle_config.chat_warpportal || !sd->chatID)
-                    {
-                        if ((sg->val1--) > 0)
-                        {
-                            pc_setpos(sd, sg->valstr, sg->val2 >> 16,
-                                       sg->val2 & 0xffff, 3);
-                            if (sg->src_id == bl->id
-                                || (strcmp(map[src->bl.m].name, sg->valstr)
-                                    == 0 && src->bl.x == (sg->val2 >> 16)
-                                    && src->bl.y == (sg->val2 & 0xffff)))
-                                skill_delunitgroup(sg);
-                        }
-                        else
-                            skill_delunitgroup(sg);
-                    }
-                }
-            }
-            else if (bl->type == BL_MOB && battle_config.mob_warpportal)
-            {
-                int m = map_mapname2mapid(sg->valstr);
-                mob_warp((struct mob_data *) bl, m, sg->val2 >> 16,
-                          sg->val2 & 0xffff, 3);
-            }
-            break;
+    nullpo_retr(1, bl);
 
-        case 0x8e:             /* クァグマイア */
-        {
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (bl->type == BL_PC
-                && ((struct map_session_data *) bl)->
-                special_state.no_magic_damage)
-                break;
-            if (battle_get_sc_data(bl)[type].timer == -1)
-                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
-                                           0, 0,
-                                           skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv), 0);
-        }
-            break;
-        case 0x92:             /* ベノムダスト */
-        {
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sc_data && sc_data[type].timer == -1)
-                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
-                                           0, 0,
-                                           skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv), 0);
-        }
-            break;
-        case 0x9a:             /* ボルケーノ */
-        case 0x9b:             /* デリュージ */
-        case 0x9c:             /* バイオレントゲイル */
-        {
-            struct skill_unit *unit2;
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sc_data && sc_data[type].timer == -1)
-                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
-                                           0, 0,
-                                           skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv), 0);
-            else if ((unit2 = (struct skill_unit *) sc_data[type].val2)
-                     && unit2 != src)
-            {
-                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
-                    skill_status_change_start(bl, type, sg->skill_lv,
-                                               (int) src, 0, 0,
-                                               skill_get_time2(sg->skill_id,
-                                                                sg->skill_lv),
-                                               0);
-                ts->tick -= sg->interval;
-            }
-        } break;
-
-        case 0x9e:             /* 子守唄 */
-        case 0x9f:             /* ニヨルドの宴 */
-        case 0xa0:             /* 永遠の混沌 */
-        case 0xa1:             /* 戦太鼓の響き */
-        case 0xa2:             /* ニーベルングの指輪 */
-        case 0xa3:             /* ロキの叫び */
-        case 0xa4:             /* 深淵の中に */
-        case 0xa5:             /* 不死身のジークフリード */
-        case 0xa6:             /* 不協和音 */
-        case 0xa7:             /* 口笛 */
-        case 0xa8:             /* 夕陽のアサシンクロス */
-        case 0xa9:             /* ブラギの詩 */
-        case 0xab:             /* 自分勝手なダンス */
-        case 0xac:             /* ハミング */
-        case 0xad:             /* 私を忘れないで… */
-        case 0xae:             /* 幸運のキス */
-        case 0xaf:             /* サービスフォーユー */
-        case 0xb4:
-        {
-            struct skill_unit *unit2;
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sg->src_id == bl->id)
-                break;
-            if (sc_data && sc_data[type].timer == -1)
-                skill_status_change_start(bl, type, sg->skill_lv, sg->val1,
-                                           sg->val2, (int) src,
-                                           skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv), 0);
-            else if ((unit2 = (struct skill_unit *) sc_data[type].val4)
-                     && unit2 != src)
-            {
-                if (unit2->group
-                    && DIFF_TICK(sg->tick, unit2->group->tick) > 0)
-                    skill_status_change_start(bl, type, sg->skill_lv,
-                                               sg->val1, sg->val2, (int) src,
-                                               skill_get_time2(sg->skill_id,
-                                                                sg->skill_lv),
-                                               0);
-                ts->tick -= sg->interval;
-            }
-        } break;
+    if ((md = (struct map_session_data *) bl) == NULL
+        || (sd = map_id2sd(target)) == NULL)
+        return 1;
+    else
+        r = distance(bl->x, bl->y, sd->bl.x, sd->bl.y);
 
-        case 0xaa:             /* イドゥンの林檎 */
-        {
-            struct skill_unit *unit2;
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sg->src_id == bl->id)
-                break;
-            if (sc_data && sc_data[type].timer == -1)
-                skill_status_change_start(bl, type, sg->skill_lv,
-                                           (sg->val1) >> 16,
-                                           (sg->val1) & 0xffff, (int) src,
-                                           skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv), 0);
-            else if ((unit2 = (struct skill_unit *) sc_data[type].val4)
-                     && unit2 != src)
-            {
-                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
-                    skill_status_change_start(bl, type, sg->skill_lv,
-                                               (sg->val1) >> 16,
-                                               (sg->val1) & 0xffff, (int) src,
-                                               skill_get_time2(sg->skill_id,
-                                                                sg->skill_lv),
-                                               0);
-                ts->tick -= sg->interval;
-            }
-        } break;
-
-        case 0xb1:             /* デモンストレーション */
-            skill_attack(BF_WEAPON, ss, &src->bl, bl, sg->skill_id,
-                          sg->skill_lv, tick, BCT_ZERO);
-            if (bl->type == BL_PC && MRAND(100) < sg->skill_lv
-                && battle_config.equipment_breaking)
-                pc_breakweapon((struct map_session_data *) bl);
-            break;
-        case 0x99:             /* トーキーボックス */
-            if (sg->src_id == bl->id)   //自分が踏んでも発動しない
-                break;
-            if (sg->val2 == 0)
-            {
-                sg->unit_id = 0x8c;
-                clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
-                sg->limit = DIFF_TICK(tick, sg->tick) + 5000;
-                sg->val2 = -1;  //踏んだ
-            }
-            break;
-        case 0xb2:             /* あなたを_会いたいです */
-        case 0xb3:             /* ゴスペル */
-        case 0xb6:             /* フォグウォール */
-            //とりあえず何もしない
-            break;
+    if ( + 6 < r)
+    {                           // 許容範囲を超えてた
+        for (n = 0; n < 5; n++)
+            if (md->dev.val1[n] == target)
+                md->dev.val2[n] = 0;    // 離れた時は、糸を切るだけ
+        return 1;
+    }
+    return 0;
+}
 
-        case 0xb7:             /* スパイダーウェッブ */
-            if (sg->val2 == 0)
-            {
-                int moveblock = (bl->x / BLOCK_SIZE != src->bl.x / BLOCK_SIZE
-                                  || bl->y / BLOCK_SIZE !=
-                                  src->bl.y / BLOCK_SIZE);
-                skill_additional_effect(ss, bl, sg->skill_id, sg->skill_lv,
-                                         BF_MISC, tick);
-                if (moveblock)
-                    map_delblock(bl);
-                bl->x = (&src->bl)->x;
-                bl->y = (&src->bl)->y;
-                if (moveblock)
-                    map_addblock(bl);
-                if (bl->type == BL_MOB)
-                    clif_fixmobpos((struct mob_data *) bl);
-                else
-                    clif_fixpos(bl);
-                sg->limit =
-                    DIFF_TICK(tick,
-                               sg->tick) + skill_get_time2(sg->skill_id,
-                                                            sg->skill_lv);
-                sg->val2 = bl->id;
-            }
-            break;
+void skill_devotion_end(struct map_session_data *md,
+                         struct map_session_data *, int target)
+{
+    // クルセと被ディボキャラのリセット
+    nullpo_retv(md);
 
-/*      default:
-                if (battle_config.error_log)
-                        PRINTF("skill_unit_onplace: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
-                break;*/
-    }
-    if (bl->type == BL_MOB && ss != bl) /* スキル使用条件のMOBスキル */
-    {
-        if (battle_config.mob_changetarget_byskill == 1)
-        {
-            int target = ((struct mob_data *) bl)->target_id;
-            if (ss->type == BL_PC)
-                ((struct mob_data *) bl)->target_id = ss->id;
-            mobskill_use((struct mob_data *) bl, tick,
-                          MSC_SKILLUSED, sg->skill_id);
-            ((struct mob_data *) bl)->target_id = target;
-        }
-        else
-            mobskill_use((struct mob_data *) bl, tick,
-                          MSC_SKILLUSED, sg->skill_id);
-    }
+    md->dev.val1[target] = md->dev.val2[target] = 0;
+}
 
+int skill_gangsterparadise(struct map_session_data *, int)
+{
     return 0;
 }
 
+/*----------------------------------------------------------------------------
+ * ステータス異常
+ *----------------------------------------------------------------------------
+ */
+
 /*==========================================
- * スキルユニットから離脱する(もしくはしている)場合
+ * ステータス異常終了
  *------------------------------------------
  */
-static
-int skill_unit_onout(struct skill_unit *src, struct block_list *bl,
-                      unsigned int tick)
+int skill_status_change_active(struct block_list *bl, StatusChange type)
 {
-    struct skill_unit_group *sg;
+    eptr<struct status_change, StatusChange> sc_data;
 
-    nullpo_ret(src);
     nullpo_ret(bl);
-    nullpo_ret(sg = src->group);
-
-    if (bl->prev == NULL || !src->alive)
+    if (bl->type != BL_PC && bl->type != BL_MOB)
+    {
+        if (battle_config.error_log)
+            PRINTF("skill_status_change_active: neither MOB nor PC !\n");
         return 0;
+    }
 
-    if (bl->type != BL_PC && bl->type != BL_MOB)
+    sc_data = battle_get_sc_data(bl);
+    if (not sc_data)
         return 0;
 
-    switch (sg->unit_id)
-    {
-        case 0x7e:             /* セイフティウォール */
-        case 0x85:             /* ニューマ */
-        case 0x8e:             /* クァグマイア */
-        {
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            StatusChange type =
-                (sg->unit_id == 0x85) ? SC_PNEUMA : SC_SAFETYWALL;
-            if (sc_data
-                && sc_data[type].timer != -1
-                && ((struct skill_unit *) sc_data[type].val2) == src)
-            {
-                skill_status_change_end(bl, type, -1);
-            }
-        } break;
+    return sc_data[type].timer != -1;
+}
 
-        case 0x91:             /* アンクルスネア */
-        {
-            struct block_list *target = map_id2bl(sg->val2);
-            if (target && target == bl)
+int skill_status_change_end(struct block_list *bl, StatusChange type, int tid)
+{
+    eptr<struct status_change, StatusChange> sc_data;
+    int opt_flag = 0, calc_flag = 0;
+    short *sc_count;
+    Option *option;
+    Opt1 *opt1;
+    Opt2 *opt2;
+    Opt3 *opt3;
+
+    nullpo_ret(bl);
+    if (bl->type != BL_PC && bl->type != BL_MOB)
+    {
+        if (battle_config.error_log)
+            PRINTF("skill_status_change_end: neither MOB nor PC !\n");
+        return 0;
+    }
+    sc_data = battle_get_sc_data(bl);
+    if (not sc_data)
+        return 0;
+    sc_count = battle_get_sc_count(bl);
+    nullpo_ret(sc_count);
+    option = battle_get_option(bl);
+    nullpo_ret(option);
+    opt1 = battle_get_opt1(bl);
+    nullpo_ret(opt1);
+    opt2 = battle_get_opt2(bl);
+    nullpo_ret(opt2);
+    opt3 = battle_get_opt3(bl);
+    nullpo_ret(opt3);
+
+    if ((*sc_count) > 0 && sc_data[type].timer != -1
+        && (sc_data[type].timer == tid || tid == -1))
+    {
+
+        if (tid == -1)          // タイマから呼ばれていないならタイマ削除をする
+            delete_timer(sc_data[type].timer, skill_status_change_timer);
+
+        /* 該当の異常を正常に戻す */
+        sc_data[type].timer = -1;
+        (*sc_count)--;
+
+        switch (type)
+        {                       /* 異常の種類ごとの処理 */
+            case SC_SPEEDPOTION0:  /* 増速ポーション */
+            case SC_ATKPOT:    /* attack potion [Valaris] */
+            case SC_MATKPOT:   /* magic attack potion [Valaris] */
+            case SC_PHYS_SHIELD:
+            case SC_HASTE:
+                calc_flag = 1;
+                break;
             {
-                skill_status_change_end(bl, SC_ANKLE, -1);
-                sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
+                struct map_session_data *md = map_id2sd(sc_data[type].val1);
+                sc_data[type].val1 = sc_data[type].val2 = 0;
+                skill_devotion(md, bl->id);
+                calc_flag = 1;
             }
-        }
-            break;
-        case 0xb5:
-        case 0xb8:
-        {
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
-        }
-            break;
-        case 0xb6:
-        {
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
-        }
-            break;
-        case 0x9a:             /* ボルケーノ */
-        case 0x9b:             /* デリュージ */
-        case 0x9c:             /* バイオレントゲイル */
-        {
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            struct skill_unit *su;
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sc_data && sc_data[type].timer != -1
-                && (su = ((struct skill_unit *) sc_data[type].val2))
-                && su == src)
+                break;
+            case SC_NOCHAT:    //チャット禁止状態
+                break;
+            case SC_SELFDESTRUCTION:   /* 自爆 */
             {
-                skill_status_change_end(bl, type, -1);
+                //自分のダメージは0にして
+                struct mob_data *md = NULL;
+                if (bl->type == BL_MOB && (md = (struct mob_data *) bl))
+                    skill_castend_damage_id(bl, bl,
+                           static_cast<SkillID>(sc_data[type].val2), sc_data[type].val1,
+                           gettick(), BCT_ZERO);
             }
-        }
-            break;
+                break;
+                /* option1 */
+            case SC_FREEZE:
+                sc_data[type].val3 = 0;
+                break;
 
-        case 0x9e:             /* 子守唄 */
-        case 0x9f:             /* ニヨルドの宴 */
-        case 0xa0:             /* 永遠の混沌 */
-        case 0xa1:             /* 戦太鼓の響き */
-        case 0xa2:             /* ニーベルングの指輪 */
-        case 0xa3:             /* ロキの叫び */
-        case 0xa4:             /* 深淵の中に */
-        case 0xa5:             /* 不死身のジークフリード */
-        case 0xa6:             /* 不協和音 */
-        case 0xa7:             /* 口笛 */
-        case 0xa8:             /* 夕陽のアサシンクロス */
-        case 0xa9:             /* ブラギの詩 */
-        case 0xaa:             /* イドゥンの林檎 */
-        case 0xab:             /* 自分勝手なダンス */
-        case 0xac:             /* ハミング */
-        case 0xad:             /* 私を忘れないで… */
-        case 0xae:             /* 幸運のキス */
-        case 0xaf:             /* サービスフォーユー */
-        case 0xb4:
-        {
-            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
-            struct skill_unit *su;
-            StatusChange type = SkillStatusChangeTable[sg->skill_id];
-            if (sc_data && sc_data[type].timer != -1
-                && (su = ((struct skill_unit *) sc_data[type].val4))
-                && su == src)
-            {
-                skill_status_change_end(bl, type, -1);
-            }
-        }
-            break;
-        case 0xb7:             /* スパイダーウェッブ */
-        {
-            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
+                /* option2 */
+            case SC_POISON:    /* 毒 */
+            case SC_BLIND:     /* 暗黒 */
+            case SC_CURSE:
+                calc_flag = 1;
+                break;
         }
-            break;
 
-/*      default:
-                if (battle_config.error_log)
-                        PRINTF("skill_unit_onout: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
-                break;*/
-    }
-    skill_unitgrouptickset_delete(bl, sg->group_id);
-    return 0;
-}
+        if (bl->type == BL_PC && type < SC_SENDMAX)
+            clif_status_change(bl, type, 0);   /* アイコン消去 */
 
-/*==========================================
- * スキルユニットの削除イベント
- *------------------------------------------
- */
-static
-int skill_unit_ondelete(struct skill_unit *src, struct block_list *bl,
-                         unsigned int tick)
-{
-    struct skill_unit_group *sg;
+        switch (type)
+        {                       /* 正常に戻るときなにか処理が必要 */
+            case SC_STONE:
+            case SC_FREEZE:
+            case SC_STAN:
+            case SC_SLEEP:
+                *opt1 = Opt1::ZERO;
+                opt_flag = 1;
+                break;
 
-    nullpo_ret(src);
-    nullpo_ret(bl);
-    nullpo_ret(sg = src->group);
+            case SC_POISON:
+                *opt2 &= ~Opt2::_poison;
+                opt_flag = 1;
+                break;
 
-    if (bl->prev == NULL || !src->alive)
-        return 0;
+            case SC_CURSE:
+                *opt2 &= ~Opt2::_curse;
+                opt_flag = 1;
+                break;
 
-    if (bl->type != BL_PC && bl->type != BL_MOB)
-        return 0;
+            case SC_SILENCE:
+                *opt2 &= ~Opt2::_silence;
+                opt_flag = 1;
+                break;
 
-    switch (sg->unit_id)
-    {
-        case 0x85:             /* ニューマ */
-        case 0x7e:             /* セイフティウォール */
-        case 0x8e:             /* クァグマイヤ */
-        case 0x9a:             /* ボルケーノ */
-        case 0x9b:             /* デリュージ */
-        case 0x9c:             /* バイオレントゲイル */
-        case 0x9e:             /* 子守唄 */
-        case 0x9f:             /* ニヨルドの宴 */
-        case 0xa0:             /* 永遠の混沌 */
-        case 0xa1:             /* 戦太鼓の響き */
-        case 0xa2:             /* ニーベルングの指輪 */
-        case 0xa3:             /* ロキの叫び */
-        case 0xa4:             /* 深淵の中に */
-        case 0xa5:             /* 不死身のジークフリード */
-        case 0xa6:             /* 不協和音 */
-        case 0xa7:             /* 口笛 */
-        case 0xa8:             /* 夕陽のアサシンクロス */
-        case 0xa9:             /* ブラギの詩 */
-        case 0xaa:             /* イドゥンの林檎 */
-        case 0xab:             /* 自分勝手なダンス */
-        case 0xac:             /* ハミング */
-        case 0xad:             /* 私を忘れないで… */
-        case 0xae:             /* 幸運のキス */
-        case 0xaf:             /* サービスフォーユー */
-        case 0xb4:
-            return skill_unit_onout(src, bl, tick);
-
-/*      default:
-                if (battle_config.error_log)
-                        PRINTF("skill_unit_ondelete: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
-                break;*/
-    }
-    skill_unitgrouptickset_delete(bl, sg->group_id);
-    return 0;
-}
+            case SC_BLIND:
+                *opt2 &= ~Opt2::BLIND;
+                opt_flag = 1;
+                break;
 
-/*==========================================
- * スキルユニットの限界イベント
- *------------------------------------------
- */
-static
-int skill_unit_onlimit(struct skill_unit *src, unsigned int)
-{
-    struct skill_unit_group *sg;
+            case SC_SLOWPOISON:
+                if (sc_data[SC_POISON].timer != -1)
+                    *opt2 |= Opt2::_poison;
+                *opt2 &= ~Opt2::_slowpoison;
+                opt_flag = 1;
+                break;
 
-    nullpo_ret(src);
-    nullpo_ret(sg = src->group);
+            case SC_SPEEDPOTION0:
+                *opt2 &= ~Opt2::_speedpotion0;
+                opt_flag = 1;
+                break;
 
-    switch (sg->unit_id)
-    {
-        case 0x81:             /* ワープポータル(発動前) */
-        {
-            struct skill_unit_group *group =
-                skill_unitsetting(map_id2bl(sg->src_id), sg->skill_id,
-                                   sg->skill_lv,
-                                   src->bl.x, src->bl.y, 1);
-            if (group == NULL)
-                return 0;
-            CREATE(group->valstr, char, 24);
-            memcpy(group->valstr, sg->valstr, 24);
-            group->val2 = sg->val2;
+            case SC_ATKPOT:
+                *opt2 &= ~Opt2::_atkpot;
+                opt_flag = 1;
+                break;
         }
-            break;
-
-        case 0x8d:             /* アイスウォール */
-            map_setcell(src->bl.m, src->bl.x, src->bl.y, src->val2);
-            break;
-        case 0xb2:             /* あなたに会いたい */
-        {
-            struct map_session_data *sd = NULL;
-            struct map_session_data *p_sd = NULL;
-            if ((sd =
-                 (struct map_session_data *)(map_id2bl(sg->src_id))) ==
-                NULL)
-                return 0;
-            if ((p_sd = pc_get_partner(sd)) == NULL)
-                return 0;
 
-            pc_setpos(p_sd, map[src->bl.m].name, src->bl.x, src->bl.y, 3);
+        if (night_flag == 1
+            && !bool(*opt2 & Opt2::BLIND)
+            && bl->type == BL_PC)
+        {                       // by [Yor]
+            *opt2 |= Opt2::BLIND;
+            opt_flag = 1;
         }
-            break;
+
+        if (opt_flag)           /* optionの変更を伝える */
+            clif_changeoption(bl);
+
+        if (bl->type == BL_PC && calc_flag)
+            pc_calcstatus((struct map_session_data *) bl, 0);  /* ステータス再計算 */
     }
+
     return 0;
 }
 
-/*==========================================
- * スキルユニットのダメージイベント
- *------------------------------------------
- */
-int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl,
-                          int damage, unsigned int)
+int skill_update_heal_animation(struct map_session_data *sd)
 {
-    struct skill_unit_group *sg;
+    const Opt2 mask = Opt2::_heal;
 
-    nullpo_ret(src);
-    nullpo_ret(sg = src->group);
+    nullpo_ret(sd);
+    bool was_active = bool(sd->opt2 & mask);
+    bool is_active = sd->quick_regeneration_hp.amount > 0;
 
-    switch (sg->unit_id)
-    {
-        case 0x8d:             /* アイスウォール */
-            src->val1 -= damage;
-            break;
-        case 0x8f:             /* ブラストマイン */
-        case 0x98:             /* クレイモアートラップ */
-            skill_blown(bl, &src->bl, 2);  //吹き飛ばしてみる
-            break;
-        default:
-            damage = 0;
-            break;
-    }
-    return damage;
-}
+    if (was_active == is_active)
+        return 0;               // no update
+
+    if (is_active)
+        sd->opt2 |= mask;
+    else
+        sd->opt2 &= ~mask;
 
-/*---------------------------------------------------------------------------- */
+    return clif_changeoption(&sd->bl);
+}
 
 /*==========================================
- * スキル使用(詠唱完了、場所指定)
+ * ステータス異常終了タイマー
  *------------------------------------------
  */
-static
-void skill_castend_pos(timer_id tid, tick_t tick, custom_id_t id, custom_data_t)
+void skill_status_change_timer(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
 {
-    struct map_session_data *sd = map_id2sd(id) /*,*target_sd=NULL */ ;
-    int maxcount;
-
-    nullpo_retv(sd);
+    StatusChange type = static_cast<StatusChange>(data);
+    struct block_list *bl;
+    struct map_session_data *sd = NULL;
+    eptr<struct status_change, StatusChange> sc_data;
+    //short *sc_count; //使ってない?
 
-    if (sd->bl.prev == NULL)
-        return;
-    if (sd->skilltimer != tid)  /* タイマIDの確認 */
+    if ((bl = map_id2bl(id)) == NULL)
         return;
-    sd->skilltimer = -1;
-    if (pc_isdead(sd))
-    {
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
+    //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる
+    sc_data = battle_get_sc_data(bl);
+    if (not sc_data)
         return;
-    }
 
-    if (battle_config.pc_land_skill_limit)
-    {
-        maxcount = skill_get_maxcount(sd->skillid);
-        if (maxcount > 0)
-        {
-            int i, c;
-            for (i = c = 0; i < MAX_SKILLUNITGROUP; i++)
-            {
-                if (sd->skillunit[i].alive_count > 0
-                    && sd->skillunit[i].skill_id == sd->skillid)
-                    c++;
-            }
-            if (c >= maxcount)
-            {
-                clif_skill_fail(sd, sd->skillid, 0, 0);
-                sd->canact_tick = tick;
-                sd->canmove_tick = tick;
-                sd->skillitem = SkillID::NEGATIVE;
-                sd->skillitemlv = -1;
-                return;
-            }
-        }
-    }
+    if (bl->type == BL_PC)
+        sd = (struct map_session_data *) bl;
 
-    int range = skill_get_range(sd->skillid, sd->skilllv);
-    if (range < 0)
-        range = battle_get_range(&sd->bl) - (range + 1);
-    range += battle_config.pc_skill_add_range;
-    if (battle_config.skill_out_range_consume)
-    {                           // changed to allow casting when target walks out of range [Valaris]
-        if (range < distance(sd->bl.x, sd->bl.y, sd->skillx, sd->skilly))
-        {
-            clif_skill_fail(sd, sd->skillid, 0, 0);
-            sd->canact_tick = tick;
-            sd->canmove_tick = tick;
-            sd->skillitem = SkillID::NEGATIVE;
-            sd->skillitemlv = -1;
-            return;
-        }
-    }
-    if (!skill_check_condition(sd, 1))
-    {                           /* 使用条件チェック */
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return;
-    }
-    sd->skillitem = SkillID::NEGATIVE;
-    sd->skillitemlv = -1;
-    if (battle_config.skill_out_range_consume)
+    //sc_count=battle_get_sc_count(bl); //使ってない?
+
+    if (sc_data[type].timer != tid)
     {
-        if (range < distance(sd->bl.x, sd->bl.y, sd->skillx, sd->skilly))
-        {
-            clif_skill_fail(sd, sd->skillid, 0, 0);
-            sd->canact_tick = tick;
-            sd->canmove_tick = tick;
-            return;
-        }
+        if (battle_config.error_log)
+            PRINTF("skill_status_change_timer %d != %d\n", tid,
+                    sc_data[type].timer);
     }
 
-    if (battle_config.pc_skill_log)
-        PRINTF("PC %d skill castend skill=%d\n",
-                sd->bl.id, sd->skillid);
-    pc_stop_walking(sd, 0);
-}
-
+    if (sc_data[type].spell_invocation)
+    {                           // Must report termination
+        spell_effect_report_termination(sc_data[type].spell_invocation,
+                                         bl->id, type, 0);
+        sc_data[type].spell_invocation = 0;
+    }
 
-/*==========================================
- * スキル使用条件(偽で使用失敗)
- *------------------------------------------
- */
-int skill_check_condition(struct map_session_data *sd, int type)
-{
-    int hp, sp, hp_rate, sp_rate, zeny, weapon, spiritball,
-        lv, mhp;
-    int index[10], itemid[10], amount[10];
-
-    nullpo_ret(sd);
-
-    if (battle_config.gm_skilluncond > 0
-        && pc_isGM(sd) >= battle_config.gm_skilluncond)
-    {
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return 1;
-    }
-
-    if (bool(sd->opt1))
-    {
-        clif_skill_fail(sd, sd->skillid, 0, 0);
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return 0;
-    }
-    if (pc_is90overweight(sd))
-    {
-        clif_skill_fail(sd, sd->skillid, 9, 0);
-        sd->skillitem = SkillID::NEGATIVE;
-        sd->skillitemlv = -1;
-        return 0;
-    }
-
-    if (sd->skillitem == sd->skillid)
-    {                           /* アイテムの場合無条件成功 */
-        if (type & 1)
-        {
-            sd->skillitem = SkillID::NEGATIVE;
-            sd->skillitemlv = -1;
-        }
-        return 1;
-    }
-    if (bool(sd->opt1))
-    {
-        clif_skill_fail(sd, sd->skillid, 0, 0);
-        return 0;
-    }
-
-    SkillID skill = sd->skillid;
-    lv = sd->skilllv;
-    hp = skill_get_hp(skill, lv);  /* 消費HP */
-    sp = skill_get_sp(skill, lv);  /* 消費SP */
-    hp_rate = (lv <= 0) ? 0 : skill_db[skill].hp_rate[lv - 1];
-    sp_rate = (lv <= 0) ? 0 : skill_db[skill].sp_rate[lv - 1];
-    zeny = skill_get_zeny(skill, lv);
-    weapon = skill_db[skill].weapon;
-    spiritball = (lv <= 0) ? 0 : skill_db[skill].spiritball[lv - 1];
-    mhp = skill_get_mhp(skill, lv);    /* 消費HP */
-    for (int i = 0; i < 10; i++)
-    {
-        itemid[i] = skill_db[skill].itemid[i];
-        amount[i] = skill_db[skill].amount[i];
-    }
-    if (mhp > 0)
-        hp += (sd->status.max_hp * mhp) / 100;
-    if (hp_rate > 0)
-        hp += (sd->status.hp * hp_rate) / 100;
-    else
-        hp += (sd->status.max_hp * abs(hp_rate)) / 100;
-    if (sp_rate > 0)
-        sp += (sd->status.sp * sp_rate) / 100;
-    else
-        sp += (sd->status.max_sp * abs(sp_rate)) / 100;
-    if (sd->dsprate != 100)
-        sp = sp * sd->dsprate / 100;    /* 消費SP修正 */
-
-    if (!(type & 2))
-    {
-        if (hp > 0 && sd->status.hp < hp)
-        {                       /* HPチェック */
-            clif_skill_fail(sd, skill, 2, 0);  /* HP不足:失敗通知 */
-            return 0;
-        }
-        if (sp > 0 && sd->status.sp < sp)
-        {                       /* SPチェック */
-            clif_skill_fail(sd, skill, 1, 0);  /* SP不足:失敗通知 */
-            return 0;
-        }
-        if (zeny > 0 && sd->status.zeny < zeny)
-        {
-            clif_skill_fail(sd, skill, 5, 0);
-            return 0;
-        }
-        if (!(weapon & (1 << sd->status.weapon)))
-        {
-            clif_skill_fail(sd, skill, 6, 0);
-            return 0;
-        }
-        if (spiritball > 0 && sd->spiritball < spiritball)
-        {
-            clif_skill_fail(sd, skill, 0, 0);  // 氣球不足
-            return 0;
-        }
-    }
-
-    for (int i = 0; i < 10; i++)
-    {
-        index[i] = -1;
-        if (itemid[i] <= 0)
-            continue;
-        if (itemid[i] >= 715 && itemid[i] <= 717
-            && sd->special_state.no_gemstone)
-            continue;
-
-        index[i] = pc_search_inventory(sd, itemid[i]);
-        if (index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i])
-        {
-            if (itemid[i] == 716 || itemid[i] == 717)
-                clif_skill_fail(sd, skill, (7 + (itemid[i] - 716)), 0);
-            else
-                clif_skill_fail(sd, skill, 0, 0);
-            return 0;
-        }
-    }
-
-    if (!(type & 1))
-        return 1;
-
-    {
-        for (int i = 0; i < 10; i++)
-        {
-            if (index[i] >= 0)
-                pc_delitem(sd, index[i], amount[i], 0);    // アイテム消費
-        }
-    }
-
-    if (type & 2)
-        return 1;
-
-    pc_heal(sd, -sp, -hp);     // [Fate] This might suppress some dupe messages
-
-    if (zeny > 0)               // Zeny消費
-        pc_payzeny(sd, zeny);
-    if (spiritball > 0)         // 氣球消費
-        pc_delspiritball(sd, spiritball, 0);
-
-    return 1;
-}
-
-/*==========================================
- * 詠唱時間計算
- *------------------------------------------
- */
-int skill_castfix(struct block_list *bl, int time)
-{
-    struct map_session_data *sd;
-    struct mob_data *md;        // [Valaris]
-    eptr<struct status_change, StatusChange> sc_data;
-    int dex;
-    int castrate = 100;
-    SkillID skill;
-    int lv, castnodex;
-
-    nullpo_ret(bl);
-
-    if (bl->type == BL_MOB)
-    {                           // Crash fix [Valaris]
-        md = (struct mob_data *) bl;
-        skill = md->skillid;
-        lv = md->skilllv;
-    }
-
-    else
-    {
-        sd = (struct map_session_data *) bl;
-        skill = sd->skillid;
-        lv = sd->skilllv;
-    }
-
-    sc_data = battle_get_sc_data(bl);
-    dex = battle_get_dex(bl);
-
-    if (skill > MAX_SKILL_DB /*|| skill < SkillID()*/)
-        return 0;
-
-    castnodex = skill_get_castnodex(skill, lv);
-
-    if (time == 0)
-        return 0;
-    if (castnodex > 0 && bl->type == BL_PC)
-        castrate = ((struct map_session_data *) bl)->castrate;
-    else if (castnodex <= 0 && bl->type == BL_PC)
-    {
-        castrate = ((struct map_session_data *) bl)->castrate;
-        time =
-            time * castrate * (battle_config.castrate_dex_scale -
-                               dex) / (battle_config.castrate_dex_scale *
-                                       100);
-        time = time * battle_config.cast_rate / 100;
-    }
-
-    return (time > 0) ? time : 0;
-}
-
-/*==========================================
- * ディレイ計算
- *------------------------------------------
- */
-int skill_delayfix(struct block_list *bl, int time)
-{
-    eptr<struct status_change, StatusChange> sc_data;
-
-    nullpo_ret(bl);
-
-    sc_data = battle_get_sc_data(bl);
-    if (time <= 0)
-        return 0;
-
-    if (bl->type == BL_PC)
-    {
-        if (battle_config.delay_dependon_dex)   /* dexの影響を計算する */
-            time =
-                time * (battle_config.castrate_dex_scale -
-                        battle_get_dex(bl)) /
-                battle_config.castrate_dex_scale;
-        time = time * battle_config.delay_rate / 100;
-    }
-
-    return (time > 0) ? time : 0;
-}
-
-/*==========================================
- * スキル使用(ID指定)
- *------------------------------------------
- */
-int skill_use_id(struct map_session_data *sd, int target_id,
-        SkillID skill_num, int skill_lv)
-{
-    unsigned int tick;
-    int casttime = 0, delay = 0, range_;
-    int forcecast = 0;
-    struct block_list *bl;
-    eptr<struct status_change, StatusChange> sc_data;
-    tick = gettick();
-
-    nullpo_ret(sd);
-
-    if ((bl = map_id2bl(target_id)) == NULL)
-    {
-/*              if (battle_config.error_log)
-                        PRINTF("skill target not found %d\n",target_id); */
-        return 0;
-    }
-    if (sd->bl.m != bl->m || pc_isdead(sd))
-        return 0;
-
-    sc_data = sd->sc_data;
-
-    /* 沈黙や異常(ただし、グリムなどの判定をする) */
-    if (bool(sd->opt1))
-        return 0;
-
-    if (bool(sd->status.option & Option::HIDE2))
-        return 0;
-
-    if (skill_get_inf2(skill_num) & 0x200 && sd->bl.id == target_id)
-        return 0;
-
-    sd->skillid = skill_num;
-    sd->skilllv = skill_lv;
-
-    if (!skill_check_condition(sd, 0))
-        return 0;
-
-    /* 射程と障害物チェック */
-    range_ = skill_get_range(skill_num, skill_lv);
-    if (range_ < 0)
-        range_ = battle_get_range(&sd->bl) - (range_ + 1);
-    if (!battle_check_range(&sd->bl, bl, range_))
-        return 0;
-
-    pc_stopattack(sd);
-
-    casttime = skill_castfix(&sd->bl, skill_get_cast(skill_num, skill_lv));
-    delay = skill_delayfix(&sd->bl, skill_get_delay(skill_num, skill_lv));
-    sd->state.skillcastcancel = skill_db[skill_num].castcancel;
-
-    if (battle_config.pc_skill_log)
-        PRINTF("PC %d skill use target_id=%d skill=%d lv=%d cast=%d\n",
-                sd->bl.id, target_id, skill_num, skill_lv, casttime);
-
-    if (casttime > 0 || forcecast)
-    {                           /* 詠唱が必要 */
-        struct mob_data *md;
-
-        /* 詠唱反応モンスター */
-        if (bl->type == BL_MOB && (md = (struct mob_data *) bl)
-            && bool(mob_db[md->mob_class].mode & MobMode::CAST_SENSOR)
-            && md->state.state != MS_ATTACK
-            && sd->invincible_timer == -1)
-        {
-            md->target_id = sd->bl.id;
-            md->state.attackable = true;
-            md->min_chase = 13;
-        }
-    }
-
-    if (casttime <= 0)          /* 詠唱の無いものはキャンセルされない */
-        sd->state.skillcastcancel = 0;
-
-    sd->skilltarget = target_id;
-    sd->skillx = 0;
-    sd->skilly = 0;
-    sd->canact_tick = tick + casttime + delay;
-    sd->canmove_tick = tick;
-
-    if (casttime > 0)
-    {
-        sd->skilltimer = add_timer(tick + casttime, skill_castend_id, sd->bl.id, 0);
-        pc_stop_walking(sd, 0);
-    }
-    else
-    {
-        sd->skilltimer = -1;
-        skill_castend_id(sd->skilltimer, tick, sd->bl.id, 0);
-    }
-
-    return 0;
-}
-
-/*==========================================
- * スキル使用(場所指定)
- *------------------------------------------
- */
-int skill_use_pos(struct map_session_data *sd,
-        int skill_x, int skill_y,
-        SkillID skill_num, int skill_lv)
-{
-    struct block_list bl;
-    eptr<struct status_change, StatusChange> sc_data;
-    unsigned int tick;
-    int casttime = 0, delay = 0, range;
-
-    nullpo_ret(sd);
-
-    if (pc_isdead(sd))
-        return 0;
-
-    sc_data = sd->sc_data;
-
-    if (bool(sd->opt1))
-        return 0;
-
-    if (bool(sd->status.option & Option::HIDE2))
-        return 0;
-
-    sd->skillid = skill_num;
-    sd->skilllv = skill_lv;
-    sd->skillx = skill_x;
-    sd->skilly = skill_y;
-    if (!skill_check_condition(sd, 0))
-        return 0;
-
-    /* 射程と障害物チェック */
-    bl.type = BL_NUL;
-    bl.m = sd->bl.m;
-    bl.x = skill_x;
-    bl.y = skill_y;
-    range = skill_get_range(skill_num, skill_lv);
-    if (range < 0)
-        range = battle_get_range(&sd->bl) - (range + 1);
-    if (!battle_check_range(&sd->bl, &bl, range))
-        return 0;
-
-    pc_stopattack(sd);
-
-    casttime = skill_castfix(&sd->bl, skill_get_cast(skill_num, skill_lv));
-    delay = skill_delayfix(&sd->bl, skill_get_delay(skill_num, skill_lv));
-    sd->state.skillcastcancel = skill_db[skill_num].castcancel;
-
-    if (battle_config.pc_skill_log)
-        PRINTF("PC %d skill use target_pos= (%d,%d) skill=%d lv=%d cast=%d\n",
-                sd->bl.id, skill_x, skill_y,
-                skill_num, skill_lv, casttime);
-
-    if (casttime <= 0)          /* 詠唱の無いものはキャンセルされない */
-        sd->state.skillcastcancel = 0;
-
-    sd->skilltarget = 0;
-    tick = gettick();
-    sd->canact_tick = tick + casttime + delay;
-    sd->canmove_tick = tick;
-
-    if (casttime > 0)
-    {
-        sd->skilltimer = add_timer(tick + casttime, skill_castend_pos, sd->bl.id, 0);
-        pc_stop_walking(sd, 0);
-    }
-    else
-    {
-        sd->skilltimer = -1;
-        skill_castend_pos(sd->skilltimer, tick, sd->bl.id, 0);
-    }
-
-    return 0;
-}
-
-/*==========================================
- * スキル詠唱キャンセル
- *------------------------------------------
- */
-int skill_castcancel(struct block_list *bl, int type)
-{
-    int inf;
-
-    nullpo_ret(bl);
-
-    if (bl->type == BL_PC)
-    {
-        struct map_session_data *sd = (struct map_session_data *) bl;
-        unsigned long tick = gettick();
-        nullpo_ret(sd);
-        sd->canact_tick = tick;
-        sd->canmove_tick = tick;
-        if (sd->skilltimer != -1)
-        {
-            if (!type)
-            {
-                if ((inf = skill_get_inf(sd->skillid)) == 2 || inf == 32)
-                    delete_timer(sd->skilltimer, skill_castend_pos);
-                else
-                    delete_timer(sd->skilltimer, skill_castend_id);
-            }
-            else
-            {
-                if ((inf = skill_get_inf(sd->skillid_old)) == 2 || inf == 32)
-                    delete_timer(sd->skilltimer, skill_castend_pos);
-                else
-                    delete_timer(sd->skilltimer, skill_castend_id);
-            }
-            sd->skilltimer = -1;
-            clif_skillcastcancel(bl);
-        }
-
-        return 0;
-    }
-    else if (bl->type == BL_MOB)
-    {
-        struct mob_data *md = (struct mob_data *) bl;
-        nullpo_ret(md);
-        if (md->skilltimer != -1)
-        {
-            if ((inf = skill_get_inf(md->skillid)) == 2 || inf == 32)
-                delete_timer(md->skilltimer, mobskill_castend_pos);
-            else
-                delete_timer(md->skilltimer, mobskill_castend_id);
-            md->skilltimer = -1;
-            clif_skillcastcancel(bl);
-        }
-        return 0;
-    }
-    return 1;
-}
-
-/*==========================================
- * ディボーション 有効確認
- *------------------------------------------
- */
-void skill_devotion(struct map_session_data *md, int)
-{
-    // 総確認
-    int n;
-
-    nullpo_retv(md);
-
-    for (n = 0; n < 5; n++)
-    {
-        if (md->dev.val1[n])
-        {
-            struct map_session_data *sd = map_id2sd(md->dev.val1[n]);
-            // 相手が見つからない // 相手をディボしてるのが自分じゃない // 距離が離れてる
-            if (sd == NULL
-                || (md->bl.id != 0/* was something else - TODO remove this */)
-                || skill_devotion3(&md->bl, md->dev.val1[n]))
-            {
-                skill_devotion_end(md, sd, n);
-            }
-        }
-    }
-}
-
-void skill_devotion2(struct block_list *bl, int crusader)
-{
-    // 被ディボーションが歩いた時の距離チェック
-    struct map_session_data *sd = map_id2sd(crusader);
-
-    nullpo_retv(bl);
-
-    if (sd)
-        skill_devotion3(&sd->bl, bl->id);
-}
-
-int skill_devotion3(struct block_list *bl, int target)
-{
-    // クルセが歩いた時の距離チェック
-    struct map_session_data *md;
-    struct map_session_data *sd;
-    int n, r = 0;
-
-    nullpo_retr(1, bl);
-
-    if ((md = (struct map_session_data *) bl) == NULL
-        || (sd = map_id2sd(target)) == NULL)
-        return 1;
-    else
-        r = distance(bl->x, bl->y, sd->bl.x, sd->bl.y);
-
-    if ( + 6 < r)
-    {                           // 許容範囲を超えてた
-        for (n = 0; n < 5; n++)
-            if (md->dev.val1[n] == target)
-                md->dev.val2[n] = 0;    // 離れた時は、糸を切るだけ
-        return 1;
-    }
-    return 0;
-}
-
-void skill_devotion_end(struct map_session_data *md,
-                         struct map_session_data *sd, int target)
-{
-    // クルセと被ディボキャラのリセット
-    nullpo_retv(md);
-    nullpo_retv(sd);
-
-    md->dev.val1[target] = md->dev.val2[target] = 0;
-}
-
-int skill_gangsterparadise(struct map_session_data *, int)
-{
-    return 0;
-}
-
-/*==========================================
- * ランドプロテクターチェック(foreachinarea)
- *------------------------------------------
- */
-void skill_landprotector(struct block_list *, SkillID, int *)
-{
-}
-
-/*==========================================
- * イドゥンの林檎の回復処理(foreachinarea)
- *------------------------------------------
- */
-static
-void skill_idun_heal(struct block_list *bl, struct skill_unit *unit)
-{
-    struct skill_unit_group *sg;
-    int heal;
-
-    nullpo_retv(bl);
-    nullpo_retv(unit);
-    nullpo_retv(sg = unit->group);
-
-    heal =
-        30 + sg->skill_lv * 5 + ((sg->val1) >> 16) * 5 +
-        ((sg->val1) & 0xfff) / 2;
-
-    if (bl->type == BL_SKILL || bl->id == sg->src_id)
-        return;
-
-    if (bl->type == BL_PC || bl->type == BL_MOB)
-    {
-        battle_heal(NULL, bl, heal, 0, 0);
-    }
-}
-
-/*==========================================
- * 指定範囲内でsrcに対して有効なターゲットのblの数を数える(foreachinarea)
- *------------------------------------------
- */
-void skill_count_target(struct block_list *bl,
-        struct block_list *src, int *c)
-{
-    nullpo_retv(bl);
-
-    if (src == NULL)
-        return;
-    if (c == NULL)
-        return;
-    if (battle_check_target(src, bl, BCT_ENEMY) > 0)
-        (*c)++;
-}
-
-/*==========================================
- * トラップ範囲処理(foreachinarea)
- *------------------------------------------
- */
-void skill_trap_splash(struct block_list *bl,
-        struct block_list *src, int tick, int splash_count)
-{
-    struct skill_unit *unit;
-    struct skill_unit_group *sg;
-    struct block_list *ss;
-    int i;
-
-    nullpo_retv(bl);
-    nullpo_retv(src);
-    unit = (struct skill_unit *) src;
-    nullpo_retv(sg = unit->group);
-    nullpo_retv(ss = map_id2bl(sg->src_id));
-
-    if (battle_check_target(src, bl, BCT_ENEMY) > 0)
-    {
-        switch (sg->unit_id)
-        {
-            case 0x95:         /* サンドマン */
-            case 0x96:         /* フラッシャー */
-            case 0x94:         /* ショックウェーブトラップ */
-                skill_additional_effect(ss, bl, sg->skill_id, sg->skill_lv,
-                                         BF_MISC, tick);
-                break;
-            case 0x8f:         /* ブラストマイン */
-            case 0x98:         /* クレイモアートラップ */
-                for (i = 0; i < splash_count; i++)
-                {
-                    skill_attack(BF_MISC, ss, src, bl, sg->skill_id,
-                                  sg->skill_lv, tick,
-                                  (sg->val2) ? BCT_mid_x05 : BCT_ZERO);
-                }
-                // TODO: determine if this was supposed to break
-                FALLTHROUGH;
-            case 0x97:         /* フリージングトラップ */
-                skill_attack(BF_WEAPON, ss, src, bl, sg->skill_id,
-                              sg->skill_lv, tick, (sg->val2) ? BCT_mid_x05 : BCT_ZERO);
-                break;
-            default:
-                break;
-        }
-    }
-}
-
-/*----------------------------------------------------------------------------
- * ステータス異常
- *----------------------------------------------------------------------------
- */
-
-/*==========================================
- * ステータス異常タイマー範囲処理
- *------------------------------------------
- */
-void skill_status_change_timer_sub(struct block_list *bl,
-        struct block_list *src, StatusChange type, unsigned int)
-{
-    nullpo_retv(bl);
-    nullpo_retv(src);
-
-    if (bl->type != BL_PC && bl->type != BL_MOB)
-        return;
-
-    switch (type)
-    {
-        case SC_SIGHT:         /* サイト */
-            if (bool((*battle_get_option(bl)) & (Option::HIDE2 | Option::CLOAK)))
-            {
-                skill_status_change_end(bl, SC_HIDING, -1);
-            }
-            break;
-    }
-}
-
-/*==========================================
- * ステータス異常終了
- *------------------------------------------
- */
-int skill_status_change_active(struct block_list *bl, StatusChange type)
-{
-    eptr<struct status_change, StatusChange> sc_data;
-
-    nullpo_ret(bl);
-    if (bl->type != BL_PC && bl->type != BL_MOB)
-    {
-        if (battle_config.error_log)
-            PRINTF("skill_status_change_active: neither MOB nor PC !\n");
-        return 0;
-    }
-
-    sc_data = battle_get_sc_data(bl);
-    if (not sc_data)
-        return 0;
-
-    return sc_data[type].timer != -1;
-}
-
-int skill_status_change_end(struct block_list *bl, StatusChange type, int tid)
-{
-    eptr<struct status_change, StatusChange> sc_data;
-    int opt_flag = 0, calc_flag = 0;
-    short *sc_count;
-    Option *option;
-    Opt1 *opt1;
-    Opt2 *opt2;
-    Opt3 *opt3;
-
-    nullpo_ret(bl);
-    if (bl->type != BL_PC && bl->type != BL_MOB)
-    {
-        if (battle_config.error_log)
-            PRINTF("skill_status_change_end: neither MOB nor PC !\n");
-        return 0;
-    }
-    sc_data = battle_get_sc_data(bl);
-    if (not sc_data)
-        return 0;
-    nullpo_ret(sc_count = battle_get_sc_count(bl));
-    nullpo_ret(option = battle_get_option(bl));
-    nullpo_ret(opt1 = battle_get_opt1(bl));
-    nullpo_ret(opt2 = battle_get_opt2(bl));
-    nullpo_ret(opt3 = battle_get_opt3(bl));
-
-    if ((*sc_count) > 0 && sc_data[type].timer != -1
-        && (sc_data[type].timer == tid || tid == -1))
-    {
-
-        if (tid == -1)          // タイマから呼ばれていないならタイマ削除をする
-            delete_timer(sc_data[type].timer, skill_status_change_timer);
-
-        /* 該当の異常を正常に戻す */
-        sc_data[type].timer = -1;
-        (*sc_count)--;
-
-        switch (type)
-        {                       /* 異常の種類ごとの処理 */
-            case SC_HIDING:
-            case SC_SPEEDPOTION0:  /* 増速ポーション */
-            case SC_ATKPOT:    /* attack potion [Valaris] */
-            case SC_MATKPOT:   /* magic attack potion [Valaris] */
-            case SC_PHYS_SHIELD:
-            case SC_HASTE:
-                calc_flag = 1;
-                break;
-            {
-                struct map_session_data *md = map_id2sd(sc_data[type].val1);
-                sc_data[type].val1 = sc_data[type].val2 = 0;
-                skill_devotion(md, bl->id);
-                calc_flag = 1;
-            }
-                break;
-            case SC_NOCHAT:    //チャット禁止状態
-                break;
-            case SC_SELFDESTRUCTION:   /* 自爆 */
-            {
-                //自分のダメージは0にして
-                struct mob_data *md = NULL;
-                if (bl->type == BL_MOB && (md = (struct mob_data *) bl))
-                    skill_castend_damage_id(bl, bl,
-                           SkillID( sc_data[type].val2), sc_data[type].val1,
-                           gettick(), BCT_ZERO);
-            }
-                break;
-                /* option1 */
-            case SC_FREEZE:
-                sc_data[type].val3 = 0;
-                break;
-
-                /* option2 */
-            case SC_POISON:    /* 毒 */
-            case SC_BLIND:     /* 暗黒 */
-            case SC_CURSE:
-                calc_flag = 1;
-                break;
-        }
-
-        if (bl->type == BL_PC && type < SC_SENDMAX)
-            clif_status_change(bl, type, 0);   /* アイコン消去 */
-
-        switch (type)
-        {                       /* 正常に戻るときなにか処理が必要 */
-            case SC_STONE:
-            case SC_FREEZE:
-            case SC_STAN:
-            case SC_SLEEP:
-                *opt1 = Opt1::ZERO;
-                opt_flag = 1;
-                break;
-
-            case SC_POISON:
-                *opt2 &= ~Opt2::_poison;
-                opt_flag = 1;
-                break;
-
-            case SC_CURSE:
-                *opt2 &= ~Opt2::_curse;
-                opt_flag = 1;
-                break;
-
-            case SC_SILENCE:
-                *opt2 &= ~Opt2::_silence;
-                opt_flag = 1;
-                break;
-
-            case SC_BLIND:
-                *opt2 &= ~Opt2::BLIND;
-                opt_flag = 1;
-                break;
-
-            case SC_SLOWPOISON:
-                if (sc_data[SC_POISON].timer != -1)
-                    *opt2 |= Opt2::_poison;
-                *opt2 &= ~Opt2::_slowpoison;
-                opt_flag = 1;
-                break;
-
-            case SC_SPEEDPOTION0:
-                *opt2 &= ~Opt2::_speedpotion0;
-                opt_flag = 1;
-                break;
-
-            case SC_ATKPOT:
-                *opt2 &= ~Opt2::_atkpot;
-                opt_flag = 1;
-                break;
-
-            case SC_HIDING:
-                *option &= ~Option::HIDE2;
-                opt_flag = 1;
-                break;
-
-            case SC_SIGHT:
-                *option &= ~Option::SIGHT;
-                opt_flag = 1;
-                break;
-        }
-
-        if (night_flag == 1
-            && !bool(*opt2 & Opt2::BLIND)
-            && bl->type == BL_PC)
-        {                       // by [Yor]
-            *opt2 |= Opt2::BLIND;
-            opt_flag = 1;
-        }
-
-        if (opt_flag)           /* optionの変更を伝える */
-            clif_changeoption(bl);
-
-        if (bl->type == BL_PC && calc_flag)
-            pc_calcstatus((struct map_session_data *) bl, 0);  /* ステータス再計算 */
-    }
-
-    return 0;
-}
-
-int skill_update_heal_animation(struct map_session_data *sd)
-{
-    const Opt2 mask = Opt2::_heal;
-
-    nullpo_ret(sd);
-    bool was_active = bool(sd->opt2 & mask);
-    bool is_active = sd->quick_regeneration_hp.amount > 0;
-
-    if (was_active == is_active)
-        return 0;               // no update
-
-    if (is_active)
-        sd->opt2 |= mask;
-    else
-        sd->opt2 &= ~mask;
-
-    return clif_changeoption(&sd->bl);
-}
-
-/*==========================================
- * ステータス異常終了タイマー
- *------------------------------------------
- */
-void skill_status_change_timer(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
-{
-    StatusChange type = StatusChange(data);
-    struct block_list *bl;
-    struct map_session_data *sd = NULL;
-    eptr<struct status_change, StatusChange> sc_data;
-    //short *sc_count; //使ってない?
-
-    if ((bl = map_id2bl(id)) == NULL)
-        return;
-    //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる
-    sc_data = battle_get_sc_data(bl);
-    if (not sc_data)
-        return;
-
-    if (bl->type == BL_PC)
-        sd = (struct map_session_data *) bl;
-
-    //sc_count=battle_get_sc_count(bl); //使ってない?
-
-    if (sc_data[type].timer != tid)
-    {
-        if (battle_config.error_log)
-            PRINTF("skill_status_change_timer %d != %d\n", tid,
-                    sc_data[type].timer);
-    }
-
-    if (sc_data[type].spell_invocation)
-    {                           // Must report termination
-        spell_effect_report_termination(sc_data[type].spell_invocation,
-                                         bl->id, type, 0);
-        sc_data[type].spell_invocation = 0;
-    }
-
-    switch (type)
-    {                           /* 特殊な処理になる場合 */
-        case SC_HIDING:        /* ハイディング */
-            if (sd)
-            {                   /* SPがあって、時間制限の間は持続 */
-                if (sd->status.sp > 0 && (--sc_data[type].val2) > 0)
-                {
-                    if (sc_data[type].val2 % (sc_data[type].val1 + 3) == 0)
-                    {
-                        sd->status.sp--;
-                        clif_updatestatus(sd, SP_SP);
-                    }
-                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
-                                                        1000 + tick,
-                                                        skill_status_change_timer,
-                                                        bl->id, data);
-                    return;
-                }
-            }
-            break;
-
-        case SC_SIGHT:         /* サイト */
-        {
-            const int range = 7;
-            map_foreachinarea(std::bind(skill_status_change_timer_sub, ph::_1, bl, type, tick),
-                    bl->m, bl->x - range, bl->y - range,
-                    bl->x + range, bl->y + range, BL_NUL);
-
-            if ((--sc_data[type].val2) > 0)
-            {
-                sc_data[type].timer = add_timer(   /* タイマー再設定 */
-                                                    250 + tick,
-                                                    skill_status_change_timer,
-                                                    bl->id, data);
-                return;
-            }
-        }
-            break;
-
-        case SC_STONE:
-            if (sc_data[type].val2 != 0)
-            {
-                Opt1 *opt1 = battle_get_opt1(bl);
-                sc_data[type].val2 = 0;
-                sc_data[type].val4 = 0;
-                battle_stopwalking(bl, 1);
-                if (opt1)
-                {
-                    *opt1 = Opt1::_stone1;
-                    clif_changeoption(bl);
-                }
-                sc_data[type].timer =
-                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
-                               data);
-                return;
-            }
-            else if ((--sc_data[type].val3) > 0)
-            {
-                int hp = battle_get_max_hp(bl);
-                if ((++sc_data[type].val4) % 5 == 0
-                    && battle_get_hp(bl) > hp >> 2)
-                {
-                    hp = hp / 100;
-                    if (hp < 1)
-                        hp = 1;
-                    if (bl->type == BL_PC)
-                        pc_heal((struct map_session_data *) bl, -hp, 0);
-                    else if (bl->type == BL_MOB)
-                    {
-                        struct mob_data *md;
-                        if ((md = ((struct mob_data *) bl)) == NULL)
-                            break;
-                        md->hp -= hp;
-                    }
-                }
-                sc_data[type].timer =
-                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
-                               data);
-                return;
-            }
-            break;
-        case SC_POISON:
-            if (sc_data[SC_SLOWPOISON].timer == -1)
-            {
-                const int resist_poison =
-                    skill_power_bl(bl, TMW_RESIST_POISON) >> 3;
-                if (resist_poison)
-                    sc_data[type].val1 -= MRAND(resist_poison + 1);
-
-                if ((--sc_data[type].val1) > 0)
-                {
-
-                    int hp = battle_get_max_hp(bl);
-                    if (battle_get_hp(bl) > hp >> 4)
-                    {
-                        if (bl->type == BL_PC)
-                        {
-                            hp = 3 + hp * 3 / 200;
-                            pc_heal((struct map_session_data *) bl, -hp, 0);
-                        }
-                        else if (bl->type == BL_MOB)
-                        {
-                            struct mob_data *md;
-                            if ((md = ((struct mob_data *) bl)) == NULL)
-                                break;
-                            hp = 3 + hp / 200;
-                            md->hp -= hp;
-                        }
-                    }
-                    sc_data[type].timer =
-                        add_timer(1000 + tick, skill_status_change_timer,
-                                   bl->id, data);
-                }
-            }
-            else
-                sc_data[type].timer =
-                    add_timer(2000 + tick, skill_status_change_timer, bl->id,
-                               data);
-            break;
-
-            /* 時間切れ無し?? */
-        case SC_WEIGHT50:
-        case SC_WEIGHT90:
-        case SC_BROKNWEAPON:
-        case SC_BROKNARMOR:
-            if (sc_data[type].timer == tid)
-                sc_data[type].timer =
-                    add_timer(1000 * 600 + tick, skill_status_change_timer,
-                               bl->id, data);
-            return;
-
-        case SC_NOCHAT:        //チャット禁止状態
-            if (sd && battle_config.muting_players)
-            {
-                time_t timer;
-                if ((++sd->status.manner)
-                    && time(&timer) <
-                    ((sc_data[type].val2) + 60 * (0 - sd->status.manner)))
-                {               //開始からstatus.manner分経ってないので継続
-                    sc_data[type].timer = add_timer(   /* タイマー再設定(60秒) */
-                                                        60000 + tick,
-                                                        skill_status_change_timer,
-                                                        bl->id, data);
-                    return;
-                }
-            }
-            break;
-        case SC_SELFDESTRUCTION:   /* 自爆 */
-            if (--sc_data[type].val3 > 0)
-            {
-                struct mob_data *md;
-                if (bl->type == BL_MOB && (md = (struct mob_data *) bl)
-                    && md->stats[MOB_SPEED] > 250)
-                {
-                    md->stats[MOB_SPEED] -= 250;
-                    md->next_walktime = tick;
-                }
-                sc_data[type].timer = add_timer(   /* タイマー再設定 */
-                                                    1000 + tick,
-                                                    skill_status_change_timer,
-                                                    bl->id, data);
-                return;
-            }
-            break;
-
-        case SC_FLYING_BACKPACK:
-            clif_updatestatus(sd, SP_WEIGHT);
-            break;
-
-    }
-
-    skill_status_change_end(bl, type, tid);
-}
-
-/*==========================================
- * ステータス異常開始
- *------------------------------------------
- */
-int skill_status_change_start(struct block_list *bl, StatusChange type,
-        int val1, int val2, int val3, int val4,
-        int tick, int flag)
-{
-    return skill_status_effect(bl, type, val1, val2, val3, val4, tick, flag,
-                                0);
-}
-
-int skill_status_effect(struct block_list *bl, StatusChange type,
-        int val1, int val2, int val3, int val4,
-        int tick, int flag, int spell_invocation)
-{
-    struct map_session_data *sd = NULL;
-    eptr<struct status_change, StatusChange> sc_data;
-    short *sc_count;
-    Option *option;
-    Opt1 *opt1;
-    Opt2 *opt2;
-    Opt3 *opt3;
-    int opt_flag = 0, calc_flag = 0;
-    int race, elem, undead_flag;
-    SP updateflag = SP::ZERO;
-    int scdef = 0;
-
-    nullpo_ret(bl);
-    if (bl->type == BL_SKILL)
-        return 0;
-    sc_data = battle_get_sc_data(bl);
-    if (not sc_data)
-        return 0;
-    nullpo_ret(sc_count = battle_get_sc_count(bl));
-    nullpo_ret(option = battle_get_option(bl));
-    nullpo_ret(opt1 = battle_get_opt1(bl));
-    nullpo_ret(opt2 = battle_get_opt2(bl));
-    nullpo_ret(opt3 = battle_get_opt3(bl));
-
-    race = battle_get_race(bl);
-    MobMode mode = battle_get_mode(bl);
-    elem = battle_get_elem_type(bl);
-    undead_flag = battle_check_undead(race, elem);
-
-    switch (type)
-    {
-        case SC_STONE:
-        case SC_FREEZE:
-            scdef = 3 + battle_get_mdef(bl) + battle_get_luk(bl) / 3;
-            break;
-        case SC_STAN:
-        case SC_SILENCE:
-        case SC_POISON:
-            scdef = 3 + battle_get_vit(bl) + battle_get_luk(bl) / 3;
-            break;
-        case SC_SLEEP:
-        case SC_BLIND:
-            scdef = 3 + battle_get_int(bl) + battle_get_luk(bl) / 3;
-            break;
-        case SC_CURSE:
-            scdef = 3 + battle_get_luk(bl);
-            break;
-
-//      case SC_CONFUSION:
-        default:
-            scdef = 0;
-    }
-    if (scdef >= 100)
-        return 0;
-    if (bl->type == BL_PC)
-    {
-        sd = (struct map_session_data *) bl;
-
-        if (SC_STONE <= type && type <= SC_BLIND)
-        {
-            BadSC bsc = BadSC_from_SC(type);
-            /* カードによる耐性 */
-            if (sd && sd->reseff[bsc] > 0
-                && MRAND(10000) < sd->reseff[bsc])
-            {
-                if (battle_config.battle_log)
-                    PRINTF("PC %d skill_sc_start: cardによる異常耐性発動\n",
-                            sd->bl.id);
-                return 0;
-            }
-        }
-    }
-    else if (bl->type == BL_MOB)
-    {
-    }
-    else
-    {
-        if (battle_config.error_log)
-            PRINTF("skill_status_change_start: neither MOB nor PC !\n");
-        return 0;
-    }
-
-    if (type == SC_FREEZE && undead_flag && !(flag & 1))
-        return 0;
-
-    if (bool(mode & MobMode::BOSS)
-        && (type == SC_STONE
-            || type == SC_FREEZE
-            || type == SC_STAN
-            || type == SC_SLEEP
-            || type == SC_SILENCE
-        )
-        && !(flag & 1))
-    {
-        /* ボスには効かない(ただしカードによる効果は適用される) */
-        return 0;
-    }
-    if (type == SC_FREEZE || type == SC_STAN || type == SC_SLEEP)
-        battle_stopwalking(bl, 1);
-
-    if (sc_data[type].timer != -1)
-    {                           /* すでに同じ異常になっている場合タイマ解除 */
-        if (sc_data[type].val1 > val1
-            && type != SC_SPEEDPOTION0
-            && type != SC_ATKPOT
-            && type != SC_MATKPOT) // added atk and matk potions [Valaris]
-            return 0;
-        if (type >= SC_STAN && type <= SC_BLIND)
-            return 0;           /* 継ぎ足しができない状態異常である時は状態異常を行わない */
-        {
-            (*sc_count)--;
-            delete_timer(sc_data[type].timer, skill_status_change_timer);
-            sc_data[type].timer = -1;
-        }
-    }
-
-    switch (type)
-    {                           /* 異常の種類ごとの処理 */
-        case SC_SLOWPOISON:
-            if (sc_data[SC_POISON].timer == -1)
-                return 0;
-            break;
-
-        case SC_SPEEDPOTION0:  /* 増速ポーション */
-            *opt2 |= Opt2::_speedpotion0;
-            calc_flag = 1;
-            tick = 1000 * tick;
-//          val2 = 5*(2+type-SC_SPEEDPOTION0);
-            break;
-
-            /* atk & matk potions [Valaris] */
-        case SC_ATKPOT:
-            *opt2 |= Opt2::_atkpot;
-            FALLTHROUGH;
-        case SC_MATKPOT:
-            calc_flag = 1;
-            tick = 1000 * tick;
-            break;
-
-        case SC_NOCHAT:        //チャット禁止状態
-        {
-            time_t timer;
-
-            if (!battle_config.muting_players)
-                break;
-
-            tick = 60000;
-            if (!val2)
-                val2 = time(&timer);
-            // updateflag = SP_MANNER;
-        }
-            break;
-        case SC_SELFDESTRUCTION:   //自爆
-            val3 = tick / 1000;
-            tick = 1000;
-            break;
-
-            /* option1 */
-        case SC_STONE:         /* 石化 */
-            if (!(flag & 2))
-            {
-                int sc_def = battle_get_mdef(bl) * 200;
-                tick = tick - sc_def;
-            }
-            val3 = tick / 1000;
-            if (val3 < 1)
-                val3 = 1;
-            tick = 5000;
-            val2 = 1;
-            break;
-        case SC_SLEEP:         /* 睡眠 */
-            if (!(flag & 2))
-            {
-//              int sc_def = 100 - (battle_get_int(bl) + battle_get_luk(bl)/3);
-//              tick = tick * sc_def / 100;
-//              if(tick < 1000) tick = 1000;
-                tick = 30000;   //睡眠はステータス耐性に関わらず30秒
-            }
-            break;
-        case SC_FREEZE:        /* 凍結 */
-            if (!(flag & 2))
-            {
-                int sc_def = 100 - battle_get_mdef(bl);
-                tick = tick * sc_def / 100;
-            }
-            break;
-        case SC_STAN:          /* スタン(val2にミリ秒セット) */
-            if (!(flag & 2))
-            {
-                int sc_def =
-                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 3);
-                tick = tick * sc_def / 100;
-            }
-            break;
-
-            /* option2 */
-        case SC_POISON:        /* 毒 */
-            calc_flag = 1;
-            if (!(flag & 2))
-            {
-                int sc_def =
-                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 5);
-                tick = tick * sc_def / 100;
-            }
-            val3 = tick / 1000;
-            if (val3 < 1)
-                val3 = 1;
-            tick = 1000;
-            break;
-        case SC_SILENCE:       /* 沈黙(レックスデビーナ) */
-            if (!(flag & 2))
-            {
-                int sc_def = 100 - battle_get_vit(bl);
-                tick = tick * sc_def / 100;
-            }
-            break;
-        case SC_BLIND:         /* 暗黒 */
-            calc_flag = 1;
-            if (!(flag & 2))
-            {
-                int sc_def =
-                    battle_get_lv(bl) / 10 + battle_get_int(bl) / 15;
-                tick = 30000 - sc_def;
-            }
-            break;
-        case SC_CURSE:
-            calc_flag = 1;
-            if (!(flag & 2))
-            {
-                int sc_def = 100 - battle_get_vit(bl);
-                tick = tick * sc_def / 100;
-            }
-            break;
-
-            /* option */
-        case SC_HIDING:        /* ハイディング */
-            calc_flag = 1;
-            if (bl->type == BL_PC)
-            {
-                val2 = tick / 1000; /* 持続時間 */
-                tick = 1000;
-            }
-            break;
-
-        case SC_SIGHT:         /* サイト/ルアフ */
-            val2 = tick / 250;
-            tick = 10;
-            break;
-
-            /* セーフティウォール、ニューマ */
-        case SC_SAFETYWALL:
-        case SC_PNEUMA:
-            tick = ((struct skill_unit *) val2)->group->limit;
-            break;
-
-            /* アンクル */
-        case SC_ANKLE:
-            break;
-
-        case SC_WEIGHT50:
-        case SC_WEIGHT90:
-        case SC_BROKNWEAPON:
-        case SC_BROKNARMOR:
-            tick = 600 * 1000;
-            break;
-
-        case SC_HASTE:
-            calc_flag = 1;
-            break;
-        case SC_PHYS_SHIELD:
-        case SC_MBARRIER:
-        case SC_HALT_REGENERATE:
-        case SC_HIDE:
-            break;
-        case SC_FLYING_BACKPACK:
-            updateflag = SP_WEIGHT;
-            break;
-        default:
-            if (battle_config.error_log)
-                PRINTF("UnknownStatusChange [%d]\n", type);
-            return 0;
-    }
-
-    if (bl->type == BL_PC && type < SC_SENDMAX)
-        clif_status_change(bl, type, 1);   /* アイコン表示 */
-
-    /* optionの変更 */
     switch (type)
-    {
+    {                           /* 特殊な処理になる場合 */
         case SC_STONE:
-        case SC_FREEZE:
-        case SC_STAN:
-        case SC_SLEEP:
-            battle_stopattack(bl); /* 攻撃停止 */
-            skill_stop_dancing(bl, 0); /* 演奏/ダンスの中断 */
-            /* 同時に掛からないステータス異常を解除 */
-            for (StatusChange i : MAJOR_STATUS_EFFECTS_1)
+            if (sc_data[type].val2 != 0)
             {
-                if (sc_data[i].timer != -1)
+                Opt1 *opt1 = battle_get_opt1(bl);
+                sc_data[type].val2 = 0;
+                sc_data[type].val4 = 0;
+                battle_stopwalking(bl, 1);
+                if (opt1)
                 {
-                    (*sc_count)--;
-                    delete_timer(sc_data[i].timer,
-                                  skill_status_change_timer);
-                    sc_data[i].timer = -1;
+                    *opt1 = Opt1::_stone1;
+                    clif_changeoption(bl);
                 }
+                sc_data[type].timer =
+                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
+                               data);
+                return;
             }
-            switch (type)
+            else if ((--sc_data[type].val3) > 0)
             {
-            case SC_STONE:  *opt1 = Opt1::_stone6; break;
-            case SC_FREEZE: *opt1 = Opt1::_freeze; break;
-            case SC_STAN:   *opt1 = Opt1::_stan; break;
-            case SC_SLEEP:  *opt1 = Opt1::_sleep; break;
+                int hp = battle_get_max_hp(bl);
+                if ((++sc_data[type].val4) % 5 == 0
+                    && battle_get_hp(bl) > hp >> 2)
+                {
+                    hp = hp / 100;
+                    if (hp < 1)
+                        hp = 1;
+                    if (bl->type == BL_PC)
+                        pc_heal((struct map_session_data *) bl, -hp, 0);
+                    else if (bl->type == BL_MOB)
+                    {
+                        struct mob_data *md;
+                        if ((md = ((struct mob_data *) bl)) == NULL)
+                            break;
+                        md->hp -= hp;
+                    }
+                }
+                sc_data[type].timer =
+                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
+                               data);
+                return;
             }
-            opt_flag = 1;
             break;
         case SC_POISON:
             if (sc_data[SC_SLOWPOISON].timer == -1)
             {
-                *opt2 |= Opt2::_poison;
-                opt_flag = 1;
-            }
-            break;
+                const int resist_poison =
+                    skill_power_bl(bl, TMW_RESIST_POISON) >> 3;
+                if (resist_poison)
+                    sc_data[type].val1 -= MRAND(resist_poison + 1);
 
-        case SC_CURSE:
-            *opt2 |= Opt2::_curse;
-            opt_flag = 1;
-            break;
-        case SC_SILENCE:
-            *opt2 |= Opt2::_silence;
-            opt_flag = 1;
-            break;
-        case SC_BLIND:
-            *opt2 |= Opt2::BLIND;
-            opt_flag = 1;
-            break;
+                if ((--sc_data[type].val1) > 0)
+                {
 
-        case SC_SLOWPOISON:
-            *opt2 &= ~Opt2::_poison;
-            *opt2 |= Opt2::_slowpoison;
-            opt_flag = 1;
-            break;
-        case SC_HIDING:
-            battle_stopattack(bl); /* 攻撃停止 */
-            *option |= Option::HIDE2;
-            opt_flag = 1;
-            break;
-        case SC_SIGHT:
-            *option |= Option::SIGHT;
-            opt_flag = 1;
+                    int hp = battle_get_max_hp(bl);
+                    if (battle_get_hp(bl) > hp >> 4)
+                    {
+                        if (bl->type == BL_PC)
+                        {
+                            hp = 3 + hp * 3 / 200;
+                            pc_heal((struct map_session_data *) bl, -hp, 0);
+                        }
+                        else if (bl->type == BL_MOB)
+                        {
+                            struct mob_data *md;
+                            if ((md = ((struct mob_data *) bl)) == NULL)
+                                break;
+                            hp = 3 + hp / 200;
+                            md->hp -= hp;
+                        }
+                    }
+                    sc_data[type].timer =
+                        add_timer(1000 + tick, skill_status_change_timer,
+                                   bl->id, data);
+                }
+            }
+            else
+                sc_data[type].timer =
+                    add_timer(2000 + tick, skill_status_change_timer, bl->id,
+                               data);
             break;
-    }
-
-    if (opt_flag)               /* optionの変更 */
-        clif_changeoption(bl);
-
-    (*sc_count)++;              /* ステータス異常の数 */
-
-    sc_data[type].val1 = val1;
-    sc_data[type].val2 = val2;
-    sc_data[type].val3 = val3;
-    sc_data[type].val4 = val4;
-    if (sc_data[type].spell_invocation) // Supplant by newer spell
-        spell_effect_report_termination(sc_data[type].spell_invocation,
-                                         bl->id, type, 1);
-
-    sc_data[type].spell_invocation = spell_invocation;
-
-    /* タイマー設定 */
-    sc_data[type].timer =
-        add_timer(gettick() + tick, skill_status_change_timer, bl->id,
-                   custom_data_t(type));
-
-    if (bl->type == BL_PC && calc_flag)
-        pc_calcstatus(sd, 0);  /* ステータス再計算 */
-
-    if (bl->type == BL_PC && updateflag != SP::ZERO)
-        clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る */
-
-    return 0;
-}
-
-/*==========================================
- * ステータス異常全解除
- *------------------------------------------
- */
-int skill_status_change_clear(struct block_list *bl, int type)
-{
-    eptr<struct status_change, StatusChange> sc_data;
-    short *sc_count;
-    Option *option;
-    Opt1 *opt1;
-    Opt2 *opt2;
-    Opt3 *opt3;
-
-    nullpo_ret(bl);
-    sc_data = battle_get_sc_data(bl);
-    if (not sc_data)
-        return 0;
-    nullpo_ret(sc_count = battle_get_sc_count(bl));
-    nullpo_ret(option = battle_get_option(bl));
-    nullpo_ret(opt1 = battle_get_opt1(bl));
-    nullpo_ret(opt2 = battle_get_opt2(bl));
-    nullpo_ret(opt3 = battle_get_opt3(bl));
-
-    if (*sc_count == 0)
-        return 0;
-    for (StatusChange i : erange(StatusChange(), MAX_STATUSCHANGE))
-    {
-        if (sc_data[i].timer != -1)
-        {
-            skill_status_change_end(bl, i, -1);
-        }
-    }
-    *sc_count = 0;
-    *opt1 = Opt1::ZERO;
-    *opt2 = Opt2::ZERO;
-    *opt3 = Opt3::ZERO;
-    *option &= Option::MASK;
-
-    if (night_flag == 1 && type == 1)   // by [Yor]
-        *opt2 |= Opt2::BLIND;
-
-    if (type == 0 || type & 2)
-        clif_changeoption(bl);
-
-    return 0;
-}
-
-/* クローキング検査(周りに移動不可能地帯があるか) */
-int skill_check_cloaking(struct block_list *bl)
-{
-    static int dx[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
-    static int dy[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
-    int end = 1, i;
-
-    nullpo_ret(bl);
-
-    if (bl->type == BL_PC && battle_config.pc_cloak_check_type & 1)
-        return 0;
-    if (bl->type == BL_MOB && battle_config.monster_cloak_check_type & 1)
-        return 0;
-    for (i = 0; i < sizeof(dx) / sizeof(dx[0]); i++)
-    {
-        int c = map_getcell(bl->m, bl->x + dx[i], bl->y + dy[i]);
-        if (c == 1 || c == 5)
-            end = 0;
-    }
-    if (end)
-    {
-        *battle_get_option(bl) &= ~Option::CLOAK;  /* 念のための処理 */
-    }
-    return end;
-}
-
-/*
- *----------------------------------------------------------------------------
- * スキルユニット
- *----------------------------------------------------------------------------
- */
-
-/*==========================================
- * 演奏/ダンスをやめる
- * flag 1で合奏中なら相方にユニットを任せる
- *
- *------------------------------------------
- */
-void skill_stop_dancing(struct block_list *, int)
-{
-    // TODO remove this
-}
-
-/*==========================================
- * スキルユニット初期化
- *------------------------------------------
- */
-struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx,
-                                   int x, int y)
-{
-    struct skill_unit *unit;
-
-    nullpo_retr(NULL, group);
-    nullpo_retr(NULL, unit = &group->unit[idx]);
-
-    if (!unit->alive)
-        group->alive_count++;
-
-    unit->bl.id = map_addobject(&unit->bl);
-    unit->bl.type = BL_SKILL;
-    unit->bl.m = group->map;
-    unit->bl.x = x;
-    unit->bl.y = y;
-    unit->group = group;
-    unit->val1 = unit->val2 = 0;
-    unit->alive = 1;
-
-    map_addblock(&unit->bl);
-    return unit;
-}
-
-void skill_unit_timer_sub_ondelete(struct block_list *bl,
-        struct block_list *src, unsigned int tick);
-/*==========================================
- * スキルユニット削除
- *------------------------------------------
- */
-int skill_delunit(struct skill_unit *unit)
-{
-    struct skill_unit_group *group;
-    int range;
-
-    nullpo_ret(unit);
-    if (!unit->alive)
-        return 0;
-    nullpo_ret(group = unit->group);
-
-    /* onlimitイベント呼び出し */
-    skill_unit_onlimit(unit, gettick());
-
-    /* ondeleteイベント呼び出し */
-    range = group->range;
-    map_foreachinarea(std::bind(skill_unit_timer_sub_ondelete, ph::_1,  &unit->bl, gettick()),
-            unit->bl.m, unit->bl.x - range, unit->bl.y - range,
-            unit->bl.x + range, unit->bl.y + range, BL_NUL);
-
-    unit->group = NULL;
-    unit->alive = 0;
-    map_delobjectnofree(unit->bl.id, BL_SKILL);
-    if (group->alive_count > 0 && (--group->alive_count) <= 0)
-        skill_delunitgroup(group);
-
-    return 0;
-}
-
-/*==========================================
- * スキルユニットグループ初期化
- *------------------------------------------
- */
-static
-int skill_unit_group_newid = 10;
-struct skill_unit_group *skill_initunitgroup(struct block_list *src,
-        int count, SkillID skillid, int skilllv, int unit_id)
-{
-    int i;
-    struct skill_unit_group *group = NULL, *list = NULL;
-    int maxsug = 0;
 
-    nullpo_retr(NULL, src);
+            /* 時間切れ無し?? */
+        case SC_WEIGHT50:
+        case SC_WEIGHT90:
+        case SC_BROKNWEAPON:
+        case SC_BROKNARMOR:
+            if (sc_data[type].timer == tid)
+                sc_data[type].timer =
+                    add_timer(1000 * 600 + tick, skill_status_change_timer,
+                               bl->id, data);
+            return;
 
-    if (src->type == BL_PC)
-    {
-        list = ((struct map_session_data *) src)->skillunit;
-        maxsug = MAX_SKILLUNITGROUP;
-    }
-    else if (src->type == BL_MOB)
-    {
-        list = ((struct mob_data *) src)->skillunit;
-        maxsug = MAX_MOBSKILLUNITGROUP;
-    }
-    if (list)
-    {
-        for (i = 0; i < maxsug; i++)    /* 空いているもの検索 */
-            if (list[i].group_id == 0)
+        case SC_NOCHAT:        //チャット禁止状態
+            if (sd && battle_config.muting_players)
             {
-                group = &list[i];
-                break;
+                time_t timer;
+                if ((++sd->status.manner)
+                    && time(&timer) <
+                    ((sc_data[type].val2) + 60 * (0 - sd->status.manner)))
+                {               //開始からstatus.manner分経ってないので継続
+                    sc_data[type].timer = add_timer(   /* タイマー再設定(60秒) */
+                                                        60000 + tick,
+                                                        skill_status_change_timer,
+                                                        bl->id, data);
+                    return;
+                }
             }
-
-        if (group == NULL)
-        {                       /* 空いてないので古いもの検索 */
-            int j = 0;
-            unsigned maxdiff = 0, x, tick = gettick();
-            for (i = 0; i < maxsug; i++)
-                if ((x = DIFF_TICK(tick, list[i].tick)) > maxdiff)
+            break;
+        case SC_SELFDESTRUCTION:   /* 自爆 */
+            if (--sc_data[type].val3 > 0)
+            {
+                struct mob_data *md;
+                if (bl->type == BL_MOB && (md = (struct mob_data *) bl)
+                    && md->stats[MOB_SPEED] > 250)
                 {
-                    maxdiff = x;
-                    j = i;
+                    md->stats[MOB_SPEED] -= 250;
+                    md->next_walktime = tick;
                 }
-            skill_delunitgroup(&list[j]);
-            group = &list[j];
-        }
-    }
-
-    if (group == NULL)
-    {
-        PRINTF("skill_initunitgroup: error unit group !\n");
-        exit(1);
-    }
-
-    group->src_id = src->id;
-    group->party_id = battle_get_party_id(src);
-    group->group_id = skill_unit_group_newid++;
-    if (skill_unit_group_newid <= 0)
-        skill_unit_group_newid = 10;
-    CREATE(group->unit, struct skill_unit, count);
-    group->unit_count = count;
-    group->val1 = group->val2 = 0;
-    group->skill_id = skillid;
-    group->skill_lv = skilllv;
-    group->unit_id = unit_id;
-    group->map = src->m;
-    group->range = 0;
-    group->limit = 10000;
-    group->interval = 1000;
-    group->tick = gettick();
-    group->valstr = NULL;
-
-    return group;
-}
-
-/*==========================================
- * スキルユニットグループ削除
- *------------------------------------------
- */
-int skill_delunitgroup(struct skill_unit_group *group)
-{
-    int i;
+                sc_data[type].timer = add_timer(   /* タイマー再設定 */
+                                                    1000 + tick,
+                                                    skill_status_change_timer,
+                                                    bl->id, data);
+                return;
+            }
+            break;
 
-    nullpo_ret(group);
-    if (group->unit_count <= 0)
-        return 0;
+        case SC_FLYING_BACKPACK:
+            clif_updatestatus(sd, SP_WEIGHT);
+            break;
 
-    group->alive_count = 0;
-    if (group->unit != NULL)
-    {
-        for (i = 0; i < group->unit_count; i++)
-            if (group->unit[i].alive)
-                skill_delunit(&group->unit[i]);
-    }
-    if (group->valstr != NULL)
-    {
-        map_freeblock(group->valstr);
-        group->valstr = NULL;
     }
 
-    map_freeblock(group->unit);    /* free()の替わり */
-    group->unit = NULL;
-    group->src_id = 0;
-    group->group_id = 0;
-    group->unit_count = 0;
-    return 0;
+    skill_status_change_end(bl, type, tid);
 }
 
 /*==========================================
- * スキルユニットグループ全削除
+ * ステータス異常開始
  *------------------------------------------
  */
-int skill_clear_unitgroup(struct block_list *src)
+int skill_status_change_start(struct block_list *bl, StatusChange type,
+        int val1, int val2, int val3, int val4,
+        int tick, int flag)
 {
-    struct skill_unit_group *group = NULL;
-    int maxsug = 0;
-
-    nullpo_ret(src);
-
-    if (src->type == BL_PC)
-    {
-        group = ((struct map_session_data *) src)->skillunit;
-        maxsug = MAX_SKILLUNITGROUP;
-    }
-    else if (src->type == BL_MOB)
-    {
-        group = ((struct mob_data *) src)->skillunit;
-        maxsug = MAX_MOBSKILLUNITGROUP;
-    }
-    if (group)
-    {
-        int i;
-        for (i = 0; i < maxsug; i++)
-            if (group[i].group_id > 0 && group[i].src_id == src->id)
-                skill_delunitgroup(&group[i]);
-    }
-    return 0;
+    return skill_status_effect(bl, type, val1, val2, val3, val4, tick, flag,
+                                0);
 }
 
-/*==========================================
- * スキルユニットグループの被影響tick検索
- *------------------------------------------
- */
-struct skill_unit_group_tickset *skill_unitgrouptickset_search(
-        struct block_list *bl, int group_id)
+int skill_status_effect(struct block_list *bl, StatusChange type,
+        int val1, int val2, int val3, int val4,
+        int tick, int flag, int spell_invocation)
 {
-    int i, j = 0, k, s = group_id % MAX_SKILLUNITGROUPTICKSET;
-    struct skill_unit_group_tickset *set = NULL;
+    struct map_session_data *sd = NULL;
+    eptr<struct status_change, StatusChange> sc_data;
+    short *sc_count;
+    Option *option;
+    Opt1 *opt1;
+    Opt2 *opt2;
+    Opt3 *opt3;
+    int opt_flag = 0, calc_flag = 0;
+    int undead_flag;
+    SP updateflag = SP::ZERO;
+    int scdef = 0;
 
     nullpo_ret(bl);
+    sc_data = battle_get_sc_data(bl);
+    if (not sc_data)
+        return 0;
+    sc_count = battle_get_sc_count(bl);
+    nullpo_ret(sc_count);
+    option = battle_get_option(bl);
+    nullpo_ret(option);
+    opt1 = battle_get_opt1(bl);
+    nullpo_ret(opt1);
+    opt2 = battle_get_opt2(bl);
+    nullpo_ret(opt2);
+    opt3 = battle_get_opt3(bl);
+    nullpo_ret(opt3);
+
+    Race race = battle_get_race(bl);
+    MobMode mode = battle_get_mode(bl);
+    Element elem = battle_get_elem_type(bl);
+    undead_flag = battle_check_undead(race, elem);
 
-    if (bl->type == BL_PC)
-    {
-        set = ((struct map_session_data *) bl)->skillunittick;
-    }
-    else
+    switch (type)
     {
-        set = ((struct mob_data *) bl)->skillunittick;
+        case SC_STONE:
+        case SC_FREEZE:
+            scdef = 3 + battle_get_mdef(bl) + battle_get_luk(bl) / 3;
+            break;
+        case SC_STAN:
+        case SC_SILENCE:
+        case SC_POISON:
+            scdef = 3 + battle_get_vit(bl) + battle_get_luk(bl) / 3;
+            break;
+        case SC_SLEEP:
+        case SC_BLIND:
+            scdef = 3 + battle_get_int(bl) + battle_get_luk(bl) / 3;
+            break;
+        case SC_CURSE:
+            scdef = 3 + battle_get_luk(bl);
+            break;
+
+//      case SC_CONFUSION:
+        default:
+            scdef = 0;
     }
-    if (set == NULL)
+    if (scdef >= 100)
         return 0;
-    for (i = 0; i < MAX_SKILLUNITGROUPTICKSET; i++)
-        if (set[(k = (i + s) % MAX_SKILLUNITGROUPTICKSET)].group_id ==
-            group_id)
-            return &set[k];
-        else if (set[k].group_id == 0)
-            j = k;
-
-    return &set[j];
-}
-
-/*==========================================
- * スキルユニットグループの被影響tick削除
- *------------------------------------------
- */
-int skill_unitgrouptickset_delete(struct block_list *bl, int group_id)
-{
-    int i, s = group_id % MAX_SKILLUNITGROUPTICKSET;
-    struct skill_unit_group_tickset *set = NULL, *ts;
-
-    nullpo_ret(bl);
-
     if (bl->type == BL_PC)
     {
-        set = ((struct map_session_data *) bl)->skillunittick;
+        sd = (struct map_session_data *) bl;
     }
-    else
+    else if (bl->type == BL_MOB)
     {
-        set = ((struct mob_data *) bl)->skillunittick;
     }
-
-    if (set != NULL)
+    else
     {
+        if (battle_config.error_log)
+            PRINTF("skill_status_change_start: neither MOB nor PC !\n");
+        return 0;
+    }
 
-        for (i = 0; i < MAX_SKILLUNITGROUPTICKSET; i++)
-            if ((ts =
-                 &set[(i + s) % MAX_SKILLUNITGROUPTICKSET])->group_id ==
-                group_id)
-                ts->group_id = 0;
+    if (type == SC_FREEZE && undead_flag && !(flag & 1))
+        return 0;
 
+    if (bool(mode & MobMode::BOSS)
+        && (type == SC_STONE
+            || type == SC_FREEZE
+            || type == SC_STAN
+            || type == SC_SLEEP
+            || type == SC_SILENCE
+        )
+        && !(flag & 1))
+    {
+        /* ボスには効かない(ただしカードによる効果は適用される) */
+        return 0;
     }
-    return 0;
-}
+    if (type == SC_FREEZE || type == SC_STAN || type == SC_SLEEP)
+        battle_stopwalking(bl, 1);
 
-/*==========================================
- * スキルユニットタイマー発動処理用(foreachinarea)
- *------------------------------------------
- */
-static
-void skill_unit_timer_sub_onplace(struct block_list *bl,
-        struct block_list *src, unsigned int tick)
-{
-    struct skill_unit *su;
+    if (sc_data[type].timer != -1)
+    {                           /* すでに同じ異常になっている場合タイマ解除 */
+        if (sc_data[type].val1 > val1
+            && type != SC_SPEEDPOTION0
+            && type != SC_ATKPOT
+            && type != SC_MATKPOT) // added atk and matk potions [Valaris]
+            return 0;
+        if (type >= SC_STAN && type <= SC_BLIND)
+            return 0;           /* 継ぎ足しができない状態異常である時は状態異常を行わない */
+        {
+            (*sc_count)--;
+            delete_timer(sc_data[type].timer, skill_status_change_timer);
+            sc_data[type].timer = -1;
+        }
+    }
 
-    nullpo_retv(bl);
+    switch (type)
+    {                           /* 異常の種類ごとの処理 */
+        case SC_SLOWPOISON:
+            if (sc_data[SC_POISON].timer == -1)
+                return 0;
+            break;
 
-    su = (struct skill_unit *) src;
+        case SC_SPEEDPOTION0:  /* 増速ポーション */
+            *opt2 |= Opt2::_speedpotion0;
+            calc_flag = 1;
+            tick = 1000 * tick;
+//          val2 = 5*(2+type-SC_SPEEDPOTION0);
+            break;
 
-    if (su && su->alive)
-    {
-        struct skill_unit_group *sg;
-        sg = su->group;
-        if (sg && battle_check_target(src, bl, sg->target_flag) > 0)
-            skill_unit_onplace(su, bl, tick);
-    }
-}
+            /* atk & matk potions [Valaris] */
+        case SC_ATKPOT:
+            *opt2 |= Opt2::_atkpot;
+            FALLTHROUGH;
+        case SC_MATKPOT:
+            calc_flag = 1;
+            tick = 1000 * tick;
+            break;
 
-/*==========================================
- * スキルユニットタイマー削除処理用(foreachinarea)
- *------------------------------------------
- */
-void skill_unit_timer_sub_ondelete(struct block_list *bl,
-        struct block_list *src, unsigned int tick)
-{
-    struct skill_unit *su;
+        case SC_NOCHAT:        //チャット禁止状態
+        {
+            time_t timer;
 
-    nullpo_retv(bl);
+            if (!battle_config.muting_players)
+                break;
 
-    su = (struct skill_unit *) src;
+            tick = 60000;
+            if (!val2)
+                val2 = time(&timer);
+            // updateflag = SP_MANNER;
+        }
+            break;
+        case SC_SELFDESTRUCTION:   //自爆
+            val3 = tick / 1000;
+            tick = 1000;
+            break;
 
-    if (su && su->alive)
-    {
-        struct skill_unit_group *sg;
-        sg = su->group;
-        if (sg && battle_check_target(src, bl, sg->target_flag) > 0)
-            skill_unit_ondelete(su, bl, tick);
-    }
-}
+            /* option1 */
+        case SC_STONE:         /* 石化 */
+            if (!(flag & 2))
+            {
+                int sc_def = battle_get_mdef(bl) * 200;
+                tick = tick - sc_def;
+            }
+            val3 = tick / 1000;
+            if (val3 < 1)
+                val3 = 1;
+            tick = 5000;
+            val2 = 1;
+            break;
+        case SC_SLEEP:         /* 睡眠 */
+            if (!(flag & 2))
+            {
+//              int sc_def = 100 - (battle_get_int(bl) + battle_get_luk(bl)/3);
+//              tick = tick * sc_def / 100;
+//              if(tick < 1000) tick = 1000;
+                tick = 30000;   //睡眠はステータス耐性に関わらず30秒
+            }
+            break;
+        case SC_FREEZE:        /* 凍結 */
+            if (!(flag & 2))
+            {
+                int sc_def = 100 - battle_get_mdef(bl);
+                tick = tick * sc_def / 100;
+            }
+            break;
+        case SC_STAN:          /* スタン(val2にミリ秒セット) */
+            if (!(flag & 2))
+            {
+                int sc_def =
+                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 3);
+                tick = tick * sc_def / 100;
+            }
+            break;
 
-/*==========================================
- * スキルユニットタイマー処理用(foreachobject)
- *------------------------------------------
- */
-static
-void skill_unit_timer_sub(struct block_list *bl, unsigned int tick)
-{
-    struct skill_unit *unit;
-    struct skill_unit_group *group;
-    int range;
+            /* option2 */
+        case SC_POISON:        /* 毒 */
+            calc_flag = 1;
+            if (!(flag & 2))
+            {
+                int sc_def =
+                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 5);
+                tick = tick * sc_def / 100;
+            }
+            val3 = tick / 1000;
+            if (val3 < 1)
+                val3 = 1;
+            tick = 1000;
+            break;
+        case SC_SILENCE:       /* 沈黙(レックスデビーナ) */
+            if (!(flag & 2))
+            {
+                int sc_def = 100 - battle_get_vit(bl);
+                tick = tick * sc_def / 100;
+            }
+            break;
+        case SC_BLIND:         /* 暗黒 */
+            calc_flag = 1;
+            if (!(flag & 2))
+            {
+                int sc_def =
+                    battle_get_lv(bl) / 10 + battle_get_int(bl) / 15;
+                tick = 30000 - sc_def;
+            }
+            break;
+        case SC_CURSE:
+            calc_flag = 1;
+            if (!(flag & 2))
+            {
+                int sc_def = 100 - battle_get_vit(bl);
+                tick = tick * sc_def / 100;
+            }
+            break;
 
-    nullpo_retv(bl);
-    unit = (struct skill_unit *) bl;
-    nullpo_retv(group = unit->group);
+        case SC_WEIGHT50:
+        case SC_WEIGHT90:
+        case SC_BROKNWEAPON:
+        case SC_BROKNARMOR:
+            tick = 600 * 1000;
+            break;
 
-    if (!unit->alive)
-        return;
+        case SC_HASTE:
+            calc_flag = 1;
+            break;
+        case SC_PHYS_SHIELD:
+        case SC_MBARRIER:
+        case SC_HALT_REGENERATE:
+        case SC_HIDE:
+            break;
+        case SC_FLYING_BACKPACK:
+            updateflag = SP_WEIGHT;
+            break;
+        default:
+            if (battle_config.error_log)
+                PRINTF("UnknownStatusChange [%d]\n", type);
+            return 0;
+    }
 
-    range = (unit->range != 0) ? unit->range : group->range;
+    if (bl->type == BL_PC && type < SC_SENDMAX)
+        clif_status_change(bl, type, 1);   /* アイコン表示 */
 
-    /* onplaceイベント呼び出し */
-    if (unit->alive && unit->range >= 0)
-    {
-        map_foreachinarea(std::bind(skill_unit_timer_sub_onplace, ph::_1, bl, tick),
-                bl->m, bl->x - range, bl->y - range,
-                bl->x + range, bl->y + range, BL_NUL);
-        if (group->unit_id == 0xaa
-            && DIFF_TICK(tick, group->tick) >= 6000 * group->val2)
-        {
-            map_foreachinarea(std::bind(skill_idun_heal, ph::_1, unit),
-                    bl->m, bl->x - range, bl->y - range,
-                    bl->x + range, bl->y + range, BL_NUL);
-            group->val2++;
-        }
-    }
-    /* 時間切れ削除 */
-    if (unit->alive &&
-        (DIFF_TICK(tick, group->tick) >= group->limit
-         || DIFF_TICK(tick, group->tick) >= unit->limit))
+    /* optionの変更 */
+    switch (type)
     {
-        switch (group->unit_id)
-        {
-
-            case 0x8f:         /* ブラストマイン */
-                group->unit_id = 0x8c;
-                clif_changelook(bl, LOOK_BASE, group->unit_id);
-                group->limit = DIFF_TICK(tick + 1500, group->tick);
-                unit->limit = DIFF_TICK(tick + 1500, group->tick);
-                break;
-            case 0x90:         /* スキッドトラップ */
-            case 0x91:         /* アンクルスネア */
-            case 0x93:         /* ランドマイン */
-            case 0x94:         /* ショックウェーブトラップ */
-            case 0x95:         /* サンドマン */
-            case 0x96:         /* フラッシャー */
-            case 0x97:         /* フリージングトラップ */
-            case 0x98:         /* クレイモアートラップ */
-            case 0x99:         /* トーキーボックス */
+        case SC_STONE:
+        case SC_FREEZE:
+        case SC_STAN:
+        case SC_SLEEP:
+            battle_stopattack(bl); /* 攻撃停止 */
+            skill_stop_dancing(bl, 0); /* 演奏/ダンスの中断 */
+            /* 同時に掛からないステータス異常を解除 */
+            for (StatusChange i : MAJOR_STATUS_EFFECTS_1)
             {
-                struct block_list *src = map_id2bl(group->src_id);
-                if (group->unit_id == 0x91 && group->val2)
-                    ;
-                else
+                if (sc_data[i].timer != -1)
                 {
-                    if (src && src->type == BL_PC)
-                    {
-                        struct item item_tmp;
-                        memset(&item_tmp, 0, sizeof(item_tmp));
-                        item_tmp.nameid = 1065;
-                        item_tmp.identify = 1;
-                        map_addflooritem(&item_tmp, 1, bl->m, bl->x, bl->y, NULL, NULL, NULL, 0);  // 罠返還
-                    }
+                    (*sc_count)--;
+                    delete_timer(sc_data[i].timer,
+                                  skill_status_change_timer);
+                    sc_data[i].timer = -1;
                 }
             }
-                // TODO: determine if this was supposed to be break
-                FALLTHROUGH;
-            default:
-                skill_delunit(unit);
-        }
-    }
-
-    if (group->unit_id == 0x8d)
-    {
-        unit->val1 -= 5;
-        if (unit->val1 <= 0 && unit->limit + group->tick > tick + 700)
-            unit->limit = DIFF_TICK(tick + 700, group->tick);
-    }
-}
-
-/*==========================================
- * スキルユニットタイマー処理
- *------------------------------------------
- */
-static
-void skill_unit_timer(timer_id, tick_t tick, custom_id_t, custom_data_t)
-{
-    map_freeblock_lock();
-
-    map_foreachobject(std::bind(skill_unit_timer_sub, ph::_1, tick), BL_SKILL);
-
-    map_freeblock_unlock();
-}
+            switch (type)
+            {
+            case SC_STONE:  *opt1 = Opt1::_stone6; break;
+            case SC_FREEZE: *opt1 = Opt1::_freeze; break;
+            case SC_STAN:   *opt1 = Opt1::_stan; break;
+            case SC_SLEEP:  *opt1 = Opt1::_sleep; break;
+            }
+            opt_flag = 1;
+            break;
+        case SC_POISON:
+            if (sc_data[SC_SLOWPOISON].timer == -1)
+            {
+                *opt2 |= Opt2::_poison;
+                opt_flag = 1;
+            }
+            break;
 
-/*==========================================
- * スキルユニット移動時処理用(foreachinarea)
- *------------------------------------------
- */
-static
-void skill_unit_out_all_sub(struct block_list *bl,
-        struct block_list *src, unsigned int tick)
-{
-    struct skill_unit *unit;
-    struct skill_unit_group *group;
-    int range;
+        case SC_CURSE:
+            *opt2 |= Opt2::_curse;
+            opt_flag = 1;
+            break;
+        case SC_SILENCE:
+            *opt2 |= Opt2::_silence;
+            opt_flag = 1;
+            break;
+        case SC_BLIND:
+            *opt2 |= Opt2::BLIND;
+            opt_flag = 1;
+            break;
 
-    nullpo_retv(bl);
-    nullpo_retv(src);
-    unit = (struct skill_unit *) bl;
-    nullpo_retv(group = unit->group);
+        case SC_SLOWPOISON:
+            *opt2 &= ~Opt2::_poison;
+            *opt2 |= Opt2::_slowpoison;
+            opt_flag = 1;
+            break;
+    }
 
-    if (!unit->alive || src->prev == NULL)
-        return;
+    if (opt_flag)               /* optionの変更 */
+        clif_changeoption(bl);
 
-    range = (unit->range != 0) ? unit->range : group->range;
+    (*sc_count)++;              /* ステータス異常の数 */
 
-    if (range < 0 || battle_check_target(bl, src, group->target_flag) <= 0)
-        return;
+    sc_data[type].val1 = val1;
+    sc_data[type].val2 = val2;
+    sc_data[type].val3 = val3;
+    sc_data[type].val4 = val4;
+    if (sc_data[type].spell_invocation) // Supplant by newer spell
+        spell_effect_report_termination(sc_data[type].spell_invocation,
+                                         bl->id, type, 1);
 
-    if (src->x >= bl->x - range && src->x <= bl->x + range &&
-        src->y >= bl->y - range && src->y <= bl->y + range)
-        skill_unit_onout(unit, src, tick);
-}
+    sc_data[type].spell_invocation = spell_invocation;
 
-/*==========================================
- * スキルユニット移動時処理
- *------------------------------------------
- */
-int skill_unit_out_all(struct block_list *bl, unsigned int tick, int range)
-{
-    nullpo_ret(bl);
+    /* タイマー設定 */
+    sc_data[type].timer =
+        add_timer(gettick() + tick, skill_status_change_timer, bl->id,
+                   custom_data_t(type));
 
-    if (bl->prev == NULL)
-        return 0;
+    if (bl->type == BL_PC && calc_flag)
+        pc_calcstatus(sd, 0);  /* ステータス再計算 */
 
-    if (range < 7)
-        range = 7;
-    map_foreachinarea(std::bind(skill_unit_out_all_sub, ph::_1, bl, tick),
-            bl->m, bl->x - range, bl->y - range,
-            bl->x + range, bl->y + range, BL_SKILL);
+    if (bl->type == BL_PC && updateflag != SP::ZERO)
+        clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る */
 
     return 0;
 }
 
 /*==========================================
- * スキルユニット移動時処理用(foreachinarea)
+ * ステータス異常全解除
  *------------------------------------------
  */
-static
-void skill_unit_move_sub(struct block_list *bl,
-        struct block_list *src, unsigned int tick)
+int skill_status_change_clear(struct block_list *bl, int type)
 {
-    struct skill_unit *unit;
-    struct skill_unit_group *group;
-    int range;
-
-    nullpo_retv(bl);
-    nullpo_retv(unit = (struct skill_unit *) bl);
-    nullpo_retv(src);
-
-    if (!unit->alive || src->prev == NULL)
-        return;
-
-    if ((group = unit->group) == NULL)
-        return;
-    range = (unit->range != 0) ? unit->range : group->range;
-
-    if (range < 0 || battle_check_target(bl, src, group->target_flag) <= 0)
-        return;
-
-    if (src->x >= bl->x - range && src->x <= bl->x + range &&
-        src->y >= bl->y - range && src->y <= bl->y + range)
-        skill_unit_onplace(unit, src, tick);
-    else
-        skill_unit_onout(unit, src, tick);
-}
+    eptr<struct status_change, StatusChange> sc_data;
+    short *sc_count;
+    Option *option;
+    Opt1 *opt1;
+    Opt2 *opt2;
+    Opt3 *opt3;
 
-/*==========================================
- * スキルユニット移動時処理
- *------------------------------------------
- */
-int skill_unit_move(struct block_list *bl, unsigned int tick, int range)
-{
     nullpo_ret(bl);
+    sc_data = battle_get_sc_data(bl);
+    if (not sc_data)
+        return 0;
+    sc_count = battle_get_sc_count(bl);
+    nullpo_ret(sc_count);
+    option = battle_get_option(bl);
+    nullpo_ret(option);
+    opt1 = battle_get_opt1(bl);
+    nullpo_ret(opt1);
+    opt2 = battle_get_opt2(bl);
+    nullpo_ret(opt2);
+    opt3 = battle_get_opt3(bl);
+    nullpo_ret(opt3);
 
-    if (bl->prev == NULL)
+    if (*sc_count == 0)
         return 0;
+    for (StatusChange i : erange(StatusChange(), MAX_STATUSCHANGE))
+    {
+        if (sc_data[i].timer != -1)
+        {
+            skill_status_change_end(bl, i, -1);
+        }
+    }
+    *sc_count = 0;
+    *opt1 = Opt1::ZERO;
+    *opt2 = Opt2::ZERO;
+    *opt3 = Opt3::ZERO;
+    *option = Option::ZERO;
+
+    if (night_flag == 1 && type == 1)   // by [Yor]
+        *opt2 |= Opt2::BLIND;
 
-    if (range < 7)
-        range = 7;
-    map_foreachinarea(std::bind(skill_unit_move_sub, ph::_1, bl, tick),
-            bl->m, bl->x - range, bl->y - range,
-            bl->x + range, bl->y + range, BL_SKILL);
+    if (type == 0 || type & 2)
+        clif_changeoption(bl);
 
     return 0;
 }
 
-/*==========================================
- * スキルユニット自体の移動時処理(foreachinarea)
- *------------------------------------------
+/*
+ *----------------------------------------------------------------------------
+ * スキルユニット
+ *----------------------------------------------------------------------------
  */
-static
-void skill_unit_move_unit_group_sub(struct block_list *bl,
-        struct block_list *src, unsigned int tick)
-{
-    struct skill_unit *unit;
-    struct skill_unit_group *group;
-    int range;
-
-    nullpo_retv(bl);
-    nullpo_retv(src);
-    unit = (struct skill_unit *) src;
-    nullpo_retv(group = unit->group);
-
-    if (!unit->alive || bl->prev == NULL)
-        return;
-
-    range = (unit->range != 0) ? unit->range : group->range;
-
-    if (range < 0 || battle_check_target(src, bl, group->target_flag) <= 0)
-        return;
-    if (bl->x >= src->x - range && bl->x <= src->x + range &&
-        bl->y >= src->y - range && bl->y <= src->y + range)
-        skill_unit_onplace(unit, bl, tick);
-    else
-        skill_unit_onout(unit, bl, tick);
-}
 
 /*==========================================
- * スキルユニット自体の移動時処理
- * 引数はグループと移動量
+ * 演奏/ダンスをやめる
+ * flag 1で合奏中なら相方にユニットを任せる
+ *
  *------------------------------------------
  */
-int skill_unit_move_unit_group(struct skill_unit_group *group, int m, int dx,
-                                int dy)
+void skill_stop_dancing(struct block_list *, int)
 {
-    nullpo_ret(group);
-
-    if (group->unit_count <= 0)
-        return 0;
-
-    if (group->unit != NULL)
-    {
-        if (!battle_config.unit_movement_type)
-        {
-            int i;
-            for (i = 0; i < group->unit_count; i++)
-            {
-                struct skill_unit *unit = &group->unit[i];
-                if (unit->alive && !(m == unit->bl.m && dx == 0 && dy == 0))
-                {
-                    int range = unit->range;
-                    map_delblock(&unit->bl);
-                    unit->bl.m = m;
-                    unit->bl.x += dx;
-                    unit->bl.y += dy;
-                    map_addblock(&unit->bl);
-                    if (range > 0)
-                    {
-                        if (range < 7)
-                            range = 7;
-                        map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit->bl, gettick()),
-                                unit->bl.m, unit->bl.x - range, unit->bl.y - range,
-                                unit->bl.x + range, unit->bl.y + range, BL_NUL);
-                    }
-                }
-            }
-        }
-        else
-        {
-            int i, j, *r_flag, *s_flag, *m_flag;
-            struct skill_unit *unit1;
-            struct skill_unit *unit2;
-            r_flag = (int *) malloc(sizeof(int) * group->unit_count);
-            s_flag = (int *) malloc(sizeof(int) * group->unit_count);
-            m_flag = (int *) malloc(sizeof(int) * group->unit_count);
-            memset(r_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ
-            memset(s_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ
-            memset(m_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ
-
-            //先にフラグを全部決める
-            for (i = 0; i < group->unit_count; i++)
-            {
-                int move_check = 0;    // かぶりフラグ
-                unit1 = &group->unit[i];
-                for (j = 0; j < group->unit_count; j++)
-                {
-                    unit2 = &group->unit[j];
-                    if (unit1->bl.m == m && unit1->bl.x + dx == unit2->bl.x
-                        && unit1->bl.y + dy == unit2->bl.y)
-                    {
-                        //移動先にユニットがかぶってたら
-                        s_flag[i] = 1;  // 移動前のユニットナンバーの継承フラグon
-                        r_flag[j] = 1;  // かぶるユニットナンバーの残留フラグon
-                        move_check = 1; //ユニットがかぶった。
-                        break;
-                    }
-                }
-                if (!move_check)    // ユニットがかぶってなかったら
-                    m_flag[i] = 1;  // 移動前ユニットナンバーの移動フラグon
-            }
-
-            //フラグに基づいてユニット移動
-            for (i = 0; i < group->unit_count; i++)
-            {
-                unit1 = &group->unit[i];
-                if (m_flag[i])
-                {               // 移動フラグがonで
-                    if (!r_flag[i])
-                    {           // 残留フラグがoffなら
-                        //単純移動(rangeも継承の必要無し)
-                        int range = unit1->range;
-                        map_delblock(&unit1->bl);
-                        unit1->bl.m = m;
-                        unit1->bl.x += dx;
-                        unit1->bl.y += dy;
-                        map_addblock(&unit1->bl);
-                        if (range > 0)
-                        {
-                            if (range < 7)
-                                range = 7;
-                            map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit1->bl, gettick()),
-
-                                    unit1->bl.m, unit1->bl.x - range, unit1->bl.y - range,
-                                    unit1->bl.x + range, unit1->bl.y + range, BL_NUL);
-                        }
-                    }
-                    else
-                    {           // 残留フラグがonなら
-                        //空ユニットになるので、継承可能なユニットを探す
-                        for (j = 0; j < group->unit_count; j++)
-                        {
-                            unit2 = &group->unit[j];
-                            if (s_flag[j] && !r_flag[j])
-                            {
-                                // 継承移動(range継承付き)
-                                int range = unit1->range;
-                                map_delblock(&unit2->bl);
-                                unit2->bl.m = m;
-                                unit2->bl.x = unit1->bl.x + dx;
-                                unit2->bl.y = unit1->bl.y + dy;
-                                unit2->range = unit1->range;
-                                map_addblock(&unit2->bl);
-                                if (range > 0)
-                                {
-                                    if (range < 7)
-                                        range = 7;
-                                    map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit2->bl, gettick()),
-
-                                            unit2->bl.m, unit2->bl.x - range, unit2->bl.y - range,
-                                            unit2->bl.x + range, unit2->bl.y + range, BL_NUL);
-                                }
-                                s_flag[j] = 0;  // 継承完了したのでoff
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            free(r_flag);
-            free(s_flag);
-            free(m_flag);
-        }
-    }
-    return 0;
+    // TODO remove this
 }
 
+void skill_unit_timer_sub_ondelete(struct block_list *bl,
+        struct block_list *src, unsigned int tick);
+
 /*----------------------------------------------------------------------------
  * アイテム合成
  *----------------------------------------------------------------------------
@@ -4904,28 +1649,12 @@ int skill_readdb(void)
             skill_db[i].castcancel = 1;
         else
             skill_db[i].castcancel = 0;
-        skill_db[i].cast_def_rate = atoi(split[9]);
-        skill_db[i].inf2 = atoi(split[10]);
-        skill_db[i].maxcount = atoi(split[11]);
-        if (strcasecmp(split[13], "weapon") == 0)
-            skill_db[i].skill_type = BF_WEAPON;
-        else if (strcasecmp(split[12], "magic") == 0)
-            skill_db[i].skill_type = BF_MAGIC;
-        else if (strcasecmp(split[12], "misc") == 0)
-            skill_db[i].skill_type = BF_MISC;
-        else
-            skill_db[i].skill_type = BF::ZERO;
+        skill_db[i].cast_def_rate = atoi(split[10]);
+        skill_db[i].inf2 = atoi(split[11]);
+        skill_db[i].maxcount = atoi(split[12]);
+        // split[13] was one of: BF_WEAPON, BF_MAGIC, BF_MISC, BF::ZERO
         memset(split2, 0, sizeof(split2));
-        for (j = 0, p = split[14]; j < MAX_SKILL_LEVEL && p; j++)
-        {
-            split2[j] = p;
-            p = strchr(p, ':');
-            if (p)
-                *p++ = 0;
-        }
-        for (k = 0; k < MAX_SKILL_LEVEL; k++)
-            skill_db[i].blewcount[k] =
-                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);
+        // split[14] was colon-separated blow counts.
 
         if (!strcasecmp(split[15], "passive"))
         {
@@ -4981,9 +1710,6 @@ int do_init_skill(void)
 {
     skill_readdb();
 
-    add_timer_interval(gettick() + SKILLUNITTIMER_INVERVAL,
-                        skill_unit_timer, 0, 0, SKILLUNITTIMER_INVERVAL);
-
     return 0;
 }
 
diff --git a/src/map/skill.hpp b/src/map/skill.hpp
index 0966d68..7ecdd37 100644
--- a/src/map/skill.hpp
+++ b/src/map/skill.hpp
@@ -21,8 +21,6 @@ struct skill_db
     int upkeep_time[MAX_SKILL_LEVEL], upkeep_time2[MAX_SKILL_LEVEL];
     int castcancel, cast_def_rate;
     int inf2, maxcount;
-    BF skill_type;
-    int blewcount[MAX_SKILL_LEVEL];
     int hp[MAX_SKILL_LEVEL], sp[MAX_SKILL_LEVEL], mhp[MAX_SKILL_LEVEL],
         hp_rate[MAX_SKILL_LEVEL], sp_rate[MAX_SKILL_LEVEL],
         zeny[MAX_SKILL_LEVEL];
@@ -48,15 +46,12 @@ skill_name_db& skill_lookup_by_name(const char *name);
 
 struct block_list;
 struct map_session_data;
-struct skill_unit;
-struct skill_unit_group;
 
 int do_init_skill(void);
 
 // スキルデータベースへのアクセサ
 int skill_get_hit(SkillID id);
 int skill_get_inf(SkillID id);
-int skill_get_pl(SkillID id);
 int skill_get_nk(SkillID id);
 int skill_get_max(SkillID id);
 int skill_get_max_raise(SkillID id);
@@ -65,44 +60,16 @@ int skill_get_sp(SkillID id, int lv);
 int skill_get_num(SkillID id, int lv);
 int skill_get_cast(SkillID id, int lv);
 int skill_get_delay(SkillID id, int lv);
-int skill_get_time(SkillID id, int lv);
-int skill_get_time2(SkillID id, int lv);
-int skill_get_castdef(SkillID id);
-int skill_get_weapontype(SkillID id);
 int skill_get_inf2(SkillID id);
 int skill_get_maxcount(SkillID id);
-int skill_get_blewcount(SkillID id, int lv);
-
-// スキルの使用
-int skill_use_id(struct map_session_data *sd, int target_id,
-        SkillID skill_num, int skill_lv);
-int skill_use_pos(struct map_session_data *sd,
-        int skill_x, int skill_y, SkillID skill_num, int skill_lv);
-
-int skill_castend_map(struct map_session_data *sd, SkillID skill_num,
-        const char *map);
-
-int skill_cleartimerskill(struct block_list *src);
 
 // 追加効果
 int skill_additional_effect(struct block_list *src, struct block_list *bl,
         SkillID skillid, int skilllv, BF attack_type,
         unsigned int tick);
 
-int skill_delunit(struct skill_unit *unit);
-int skill_clear_unitgroup(struct block_list *src);
-
-int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl,
-        int damage, unsigned int tick);
-
 int skill_castfix(struct block_list *bl, int time);
 int skill_delayfix(struct block_list *bl, int time);
-int skill_check_unit_range(int m, int x, int y, int range, SkillID skillid);
-int skill_check_unit_range2(int m, int x, int y, int range);
-int skill_unit_out_all(struct block_list *bl, unsigned int tick, int range);
-int skill_unit_move(struct block_list *bl, unsigned int tick, int range);
-int skill_unit_move_unit_group(struct skill_unit_group *group,
-        int m, int dx, int dy);
 
 void skill_stop_dancing(struct block_list *src, int flag);
 
@@ -111,14 +78,8 @@ int skill_castcancel(struct block_list *bl, int type);
 
 int skill_gangsterparadise(struct map_session_data *sd, int type);
 void skill_devotion(struct map_session_data *md, int target);
-void skill_devotion2(struct block_list *bl, int crusader);
 int skill_devotion3(struct block_list *bl, int target);
 
-#define skill_calc_heal(bl,skill_lv) (( battle_get_lv(bl)+battle_get_int(bl) )/8 *(4+ skill_lv*8))
-
-// その他
-int skill_check_cloaking(struct block_list *bl);
-
 // ステータス異常
 int skill_status_effect(struct block_list *bl, StatusChange type,
         int val1, int val2, int val3, int val4,
diff --git a/src/map/skill.t.hpp b/src/map/skill.t.hpp
index 9dadce0..69dab85 100644
--- a/src/map/skill.t.hpp
+++ b/src/map/skill.t.hpp
@@ -28,9 +28,6 @@ enum class StatusChange : uint16_t
 #define CLIF_OPTION_SC_SCRIBE StatusChange::CLIF_OPTION_SC_SCRIBE
 
     // the rest are the normal effects
-    SC_HIDING           = 4,    // ? (opt) ?bad
-#define SC_HIDING StatusChange::SC_HIDING
-
     SC_SLOWPOISON       = 14,   // item script
 #define SC_SLOWPOISON StatusChange::SC_SLOWPOISON
 
@@ -76,9 +73,6 @@ enum class StatusChange : uint16_t
     SC_ANKLE            = 143,  // ?skill.cpp skill_unit thingies
 #define SC_ANKLE StatusChange::SC_ANKLE
 
-    SC_SIGHT            = 150,  // ?unbad
-#define SC_SIGHT StatusChange::SC_SIGHT
-
     SC_ATKPOT           = 185,  // item script
 #define SC_ATKPOT StatusChange::SC_ATKPOT
     SC_MATKPOT          = 186,  // unused, but kept for parallel
@@ -147,6 +141,7 @@ enum class BadSC
     BLIND       = 8,
 
     COUNT       = 9, // formerly 10,
+    // there is apocryphal evidence of a "bleeding" effect
 };
 
 constexpr
diff --git a/src/map/storage.cpp b/src/map/storage.cpp
index 0f3cd10..bcdf8bc 100644
--- a/src/map/storage.cpp
+++ b/src/map/storage.cpp
@@ -214,7 +214,8 @@ int storage_storageadd(struct map_session_data *sd, int index, int amount)
     struct storage *stor;
 
     nullpo_ret(sd);
-    nullpo_ret(stor = account2storage2(sd->status.account_id));
+    stor = account2storage2(sd->status.account_id);
+    nullpo_ret(stor);
 
     if ((stor->storage_amount > MAX_STORAGE) || !stor->storage_status)
         return 0;               // storage full / storage closed
@@ -249,7 +250,8 @@ int storage_storageget(struct map_session_data *sd, int index, int amount)
     PickupFail flag;
 
     nullpo_ret(sd);
-    nullpo_ret(stor = account2storage2(sd->status.account_id));
+    stor = account2storage2(sd->status.account_id);
+    nullpo_ret(stor);
 
     if (index < 0 || index >= MAX_STORAGE)
         return 0;
@@ -277,7 +279,8 @@ int storage_storageclose(struct map_session_data *sd)
     struct storage *stor;
 
     nullpo_ret(sd);
-    nullpo_ret(stor = account2storage2(sd->status.account_id));
+    stor = account2storage2(sd->status.account_id);
+    nullpo_ret(stor);
 
     clif_storageclose(sd);
     if (stor->storage_status)
-- 
cgit v1.2.3-70-g09d2