From 28f1cdc73799c43f4112f524a64fa6d3b26ba696 Mon Sep 17 00:00:00 2001
From: HoraK-FDF <horak-fdf@web.de>
Date: Thu, 3 Aug 2023 04:21:22 +0000
Subject: weapon base attack delay standardization

---
 src/ast/item_test.cpp |  2 +-
 src/char/char.cpp     |  2 +-
 src/map/atcommand.cpp |  5 ++--
 src/map/battle.cpp    |  4 +--
 src/map/clif.cpp      |  2 +-
 src/map/map.hpp       |  2 +-
 src/map/pc.cpp        | 75 ++++++++++++++++++++++++++++++---------------------
 src/mmo/clif.t.hpp    |  2 ++
 src/mmo/enums.hpp     | 31 ++++++++++++++++-----
 9 files changed, 81 insertions(+), 44 deletions(-)

(limited to 'src')

diff --git a/src/ast/item_test.cpp b/src/ast/item_test.cpp
index 7bb7193..7e5f1a9 100644
--- a/src/ast/item_test.cpp
+++ b/src/ast/item_test.cpp
@@ -135,7 +135,7 @@ namespace item
                 EXPECT_SPAN(p->elv.span, 1,42, 1,43);
                 EXPECT_EQ(p->elv.data, 13);
                 EXPECT_SPAN(p->view.span, 1,45, 1,46);
-                EXPECT_EQ(p->view.data, ItemLook::BOW);
+                EXPECT_EQ(p->view.data, ItemLook::W_BOW);
                 EXPECT_SPAN(p->use_script.span, 1,49, 1,54);
                 EXPECT_EQ(p->use_script.braced_body, "{end;}"_s);
                 EXPECT_SPAN(p->equip_script.span, 1,57, 1,58);
diff --git a/src/char/char.cpp b/src/char/char.cpp
index 8b403b3..70ad049 100644
--- a/src/char/char.cpp
+++ b/src/char/char.cpp
@@ -746,7 +746,7 @@ CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t
     cd.hair_color = hair_color;
     cd.clothes_color = 0;
     // removed initial armor/weapon - unused and problematic
-    cd.weapon = ItemLook::NONE;
+    cd.weapon = ItemLook::W_FIST;
     cd.shield = ItemNameId();
     cd.head_top = ItemNameId();
     cd.head_mid = ItemNameId();
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index b537431..8c0eb90 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -2576,9 +2576,10 @@ ATCE atcommand_character_stats_full(Session *s, dumb_ptr<map_session_data>,
                     pl_sd->hit,
                     pl_sd->hit_rate);
             clif_displaymessage(s, output);
-            output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d"_fmt,
+            output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d | BASE_WEAPON_DELAY_ADJUST: %d"_fmt,
                     pl_sd->deadly_strike,
-                    pl_sd->deadly_strike_add_rate);
+                    pl_sd->deadly_strike_add_rate,
+                    pl_sd->base_weapon_delay_adjust.count());
             clif_displaymessage(s, output);
             output = STRPRINTF("arrow_atk: %d | arrow_cri: %d | arrow_hit: %d | arrow_range: %d"_fmt,
                     pl_sd->arrow_atk,
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index eaa37a0..b745e05 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -1561,7 +1561,7 @@ struct Damage battle_calc_pc_weapon_attack(dumb_ptr<block_list> src,
         }
         OMATCH_END ();
     }
-    if (sd->status.weapon == ItemLook::BOW)
+    if (sd->status.weapon == ItemLook::W_BOW)
     {                           // 武器が弓矢の場合 | If the weapon is a bow and arrow
         atkmin = watk * ((atkmin < watk) ? atkmin : watk) / 100; // 弓用最低ATK計算 | Bows are calculated with minimum ATK
         flag = (flag & ~BF::RANGEMASK) | BF::LONG; // 遠距離攻撃フラグを有効 | Enable ranged attack flag
@@ -2058,7 +2058,7 @@ ATK battle_weapon_attack(dumb_ptr<block_list> src, dumb_ptr<block_list> target,
         battle_check_range(src, target, 0))
     {
         // 攻撃対象となりうるので攻撃 | Attack because it can be attacked
-        if (sd && sd->status.weapon == ItemLook::BOW)
+        if (sd && sd->status.weapon == ItemLook::W_BOW)
         {
             IOff0 aidx = sd->equip_index_maybe[EQUIP::ARROW];
             if (aidx.ok())
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index e81a510..9edf2af 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -3762,7 +3762,7 @@ RecvResult clif_parse_LoadEndAck(Session *s, dumb_ptr<map_session_data> sd)
     clif_equiplist(sd);
     clif_initialstatus(sd);
     clif_changeoption(sd);
-    clif_changelook(sd, LOOK::WEAPON, static_cast<uint16_t>(ItemLook::NONE));
+    clif_changelook(sd, LOOK::WEAPON, static_cast<uint16_t>(ItemLook::W_FIST));
     clif_updatestatus(sd, SP::MAXWEIGHT);
     clif_updatestatus(sd, SP::WEIGHT);
     npc_event_doall_l(stringish<ScriptLabel>("OnPCLoginEvent"_s), sd->bl_id, nullptr);
diff --git a/src/map/map.hpp b/src/map/map.hpp
index a4295fd..659ed2d 100644
--- a/src/map/map.hpp
+++ b/src/map/map.hpp
@@ -248,7 +248,7 @@ struct map_session_data : block_list, SessionData
     ItemLook weapontype1;
     earray<int, ATTR, ATTR::COUNT> paramb, paramc, parame, paramcard;
     int hit, flee, flee2;
-    interval_t aspd, amotion, dmotion;
+    interval_t aspd, amotion, dmotion, base_weapon_delay_adjust;
     int watk, watk2;
     int def, def2, mdef, mdef2, critical, matk1, matk2;
     int hprate, sprate, dsprate;
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 5196f16..63c7614 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -127,23 +127,30 @@ int sp_coefficient_0 = 100;
 static //const
 earray<interval_t, ItemLook, ItemLook::COUNT> aspd_base_0 //=
 {{
-650_ms,  // 0 NONE
-700_ms,  // 1 BLADE or some other common weapons
-750_ms,  // 2
-610_ms,  // 3 SETZER_AND_SCYTHE
-2000_ms, // 4
-2000_ms, // 5
-800_ms,  // 6 Falchion
-2000_ms, // 7
-700_ms,  // 8
-700_ms,  // 9
-650_ms,  //10 STAFF / Sandcutter
-900_ms,  //11 BOW
-2000_ms, //12
-2000_ms, //13
-2000_ms, //14
-2000_ms, //15
-2000_ms, //16
+    550_ms,  //  0 { "Fist", W_FIST },
+    600_ms,  //  1 { "Dagger", W_DAGGER },
+    650_ms,  //  2 { "Sword", W_1HSWORD },
+    700_ms,  //  3 { "TwoHandSword", W_2HSWORD },
+    650_ms,  //  4 { "Spear", W_1HSPEAR },
+    700_ms,  //  5 { "TwoHandSpear", W_2HSPEAR },
+    700_ms,  //  6 { "Axe", W_1HAXE },
+    750_ms,  //  7 { "TwoHandAxe", W_2HAXE },
+    700_ms,  //  8 { "Mace", W_MACE },
+    750_ms,  //  9 { "TwoHandMace", W_2HMACE },
+    700_ms,  // 10 { "Rod", W_STAFF },
+    800_ms,  // 11 { "Bow", W_BOW },
+    575_ms,  // 12 { "Knuckle", W_KNUCKLE },
+    800_ms,  // 13 { "Instrument", W_MUSICAL },
+    675_ms,  // 14 { "Whip", W_WHIP },
+    700_ms,  // 15 { "Book", W_BOOK },
+    600_ms,  // 16 { "Katar", W_KATAR },
+    600_ms,  // 17 { "Revolver", W_REVOLVER },
+    800_ms,  // 18 { "Rifle", W_RIFLE },
+    500_ms,  // 19 { "GatlingGun", W_GATLING },
+    1000_ms, // 20 { "Shotgun", W_SHOTGUN },
+    2000_ms, // 21 { "GrenadeLauncher", W_GRENADE },
+    650_ms,  // 22 { "FuumaShuriken", W_HUUMA },
+    750_ms,  // 23 { "TwoHandRod", W_2HSTAFF },
 }};
 
 static const
@@ -204,6 +211,7 @@ int exp_table_0[MAX_LEVEL] =
     //993241342,  1120376234, 1263784392, 1425548794, 1608019039,
     //2147483647, 0
 
+
 // is this *actually* used anywhere?
 static const
 int exp_table_7[MAX_LEVEL] =
@@ -705,7 +713,7 @@ int pc_setequipindex(dumb_ptr<map_session_data> sd)
                     }
                     OMATCH_CASE_NONE ()
                     {
-                        sd->weapontype1 = ItemLook::NONE;
+                        sd->weapontype1 = ItemLook::W_FIST;
                     }
                 }
                 OMATCH_END ();
@@ -842,7 +850,7 @@ int pc_authok(AccountId id, int login_id2, ClientVersion client_version,
     sd->state.connect_new = 1;
     sd->bl_prev = sd->bl_next = nullptr;
 
-    sd->weapontype1 = ItemLook::NONE;
+    sd->weapontype1 = ItemLook::W_FIST;
     sd->speed = DEFAULT_WALK_SPEED;
     sd->state.dead_sit = 0;
     sd->dir = DIR::S;
@@ -1130,7 +1138,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
     earray<SkillValue, SkillID, MAX_SKILL> b_skill = sd->status.skill;
     b_hit = sd->hit;
     b_flee = sd->flee;
-    interval_t b_aspd = sd->aspd;
+    interval_t b_aspd = sd->aspd, b_base_weapon_delay_adjust = interval_t::zero();
     b_watk = sd->watk;
     b_def = sd->def;
     b_watk2 = sd->watk2;
@@ -1172,7 +1180,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
     sd->flee = 0;
     sd->flee2 = 0;
     sd->critical = 0;
-    sd->aspd = interval_t::zero();
+    sd->aspd = sd->base_weapon_delay_adjust = interval_t::zero();
     sd->watk = 0;
     sd->def = 0;
     sd->mdef = 0;
@@ -1336,7 +1344,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
 
     if (sd->attackrange < 1)
         sd->attackrange = 1;
-    if (sd->status.weapon == ItemLook::BOW)
+    if (sd->status.weapon == ItemLook::W_BOW)
         sd->attackrange += sd->arrow_range;
     sd->double_rate += sd->double_add_rate;
     sd->perfect_hit += sd->perfect_hit_add_rate;
@@ -1354,7 +1362,7 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
     for (ATTR attr : ATTRs)
         sd->paramc[attr] = std::max(0, sd->status.attrs[attr] + sd->paramb[attr] + sd->parame[attr]);
 
-    if (sd->status.weapon == ItemLook::BOW)
+    if (sd->status.weapon == ItemLook::W_BOW)
     {
         str = sd->paramc[ATTR::DEX];
         dex = sd->paramc[ATTR::STR];
@@ -1448,9 +1456,12 @@ int pc_calcstatus(dumb_ptr<map_session_data> sd, int first)
 
     //二刀流 ASPD 修正 | Two-cut ASPD correction
     {
-        sd->aspd += aspd_base_0[sd->status.weapon]
+        b_base_weapon_delay_adjust = aspd_base_0[sd->status.weapon] + sd->base_weapon_delay_adjust;
+        if (b_base_weapon_delay_adjust.count() < 0)
+            b_base_weapon_delay_adjust = interval_t::zero();
+        sd->aspd += b_base_weapon_delay_adjust
             - (sd->paramc[ATTR::AGI] * 4 + sd->paramc[ATTR::DEX])
-            * aspd_base_0[sd->status.weapon] / 1000;
+            * b_base_weapon_delay_adjust / 1000;
     }
 
     aspd_rate = sd->aspd_rate;
@@ -1877,6 +1888,10 @@ int pc_bonus(dumb_ptr<map_session_data> sd, SP type, int val)
             if (!sd->state.lr_flag_is_arrow_2)
                 sd->deadly_strike_add_rate += val;
             break;
+        case SP::BASE_WEAPON_DELAY_ADJUST:
+            if (!sd->state.lr_flag_is_arrow_2)
+                sd->base_weapon_delay_adjust += interval_t(val);
+            break;
         default:
             if (battle_config.error_log)
                 PRINTF("pc_bonus: unknown type %d %d !\n"_fmt,
@@ -2897,7 +2912,7 @@ void pc_attack_timer(TimerData *, tick_t tick, BlockId id)
     {
         dist = distance(sd->bl_x, sd->bl_y, bl->bl_x, bl->bl_y);
         range = sd->attackrange;
-        if (sd->status.weapon != ItemLook::BOW)
+        if (sd->status.weapon != ItemLook::W_BOW)
             range++;
         if (dist > range)
         {                       //届 かないので移動 | Move because it does not arrive
@@ -4829,11 +4844,11 @@ int pc_equipitem(dumb_ptr<map_session_data> sd, IOff0 n, EPOS)
     sd->status.inventory[n].equip = pos;
 
     ItemNameId view_i;
-    ItemLook view_l = ItemLook::NONE;
+    ItemLook view_l = ItemLook::W_FIST;
     // TODO: This is ugly.
     OMATCH_BEGIN_SOME (sdidn, sd->inventory_data[n])
     {
-        bool look_not_weapon = sdidn->look == ItemLook::NONE;
+        bool look_not_weapon = sdidn->look == ItemLook::W_FIST;
         bool equip_is_weapon = bool(sd->status.inventory[n].equip & EPOS::WEAPON);
         assert (look_not_weapon != equip_is_weapon);
 
@@ -4922,9 +4937,9 @@ int pc_unequipitem(dumb_ptr<map_session_data> sd, IOff0 n, CalcStatus type)
         }
         if (bool(sd->status.inventory[n].equip & EPOS::WEAPON))
         {
-            sd->weapontype1 = ItemLook::NONE;
+            sd->weapontype1 = ItemLook::W_FIST;
             // when reading the diff, think twice about this
-            sd->status.weapon = ItemLook::NONE;
+            sd->status.weapon = ItemLook::W_FIST;
             pc_calcweapontype(sd);
             pc_set_weapon_look(sd);
         }
diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp
index e92c349..1d61070 100644
--- a/src/mmo/clif.t.hpp
+++ b/src/mmo/clif.t.hpp
@@ -482,6 +482,8 @@ enum class SP : uint16_t
 
     DEADLY_STRIKE_RATE          = 1091,
     DEADLY_STRIKE_ADD_RATE      = 1092,
+
+    BASE_WEAPON_DELAY_ADJUST    = 1093,
 };
 
 constexpr
diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp
index 12c82ca..c4a1b17 100644
--- a/src/mmo/enums.hpp
+++ b/src/mmo/enums.hpp
@@ -99,12 +99,31 @@ constexpr ATTR ATTRs[6] =
 
 enum class ItemLook : uint16_t
 {
-    NONE = 0,
-    BLADE = 1, // or some other common weapons
-    SETZER_AND_SCYTHE = 3,
-    STAFF = 10,
-    BOW = 11,
-    COUNT = 17,
+    W_FIST,     //  0 Fist
+    W_DAGGER,   //  1 Dagger
+    W_1HSWORD,  //  2 Sword
+    W_2HSWORD,  //  3 TwoHandSword
+    W_1HSPEAR,  //  4 Spear
+    W_2HSPEAR,  //  5 TwoHandSpear
+    W_1HAXE,    //  6 Axe
+    W_2HAXE,    //  7 TwoHandAxe
+    W_MACE,     //  8 Mace
+    W_2HMACE,   //  9 TwoHandMace
+    W_STAFF,    // 10 Rod
+    W_BOW,      // 11 Bow
+    W_KNUCKLE,  // 12 Knuckle
+    W_MUSICAL,  // 13 Instrument
+    W_WHIP,     // 14 Whip
+    W_BOOK,     // 15 Book
+    W_KATAR,    // 16 Katar
+    W_REVOLVER, // 17 Revolver
+    W_RIFLE,    // 18 Rifle
+    W_GATLING,  // 19 GatlingGun
+    W_SHOTGUN,  // 20 Shotgun
+    W_GRENADE,  // 21 GrenadeLauncher
+    W_HUUMA,    // 22 FuumaShuriken
+    W_2HSTAFF,  // 23 TwoHandRod
+    COUNT,
 };
 
 namespace e
-- 
cgit v1.2.3-70-g09d2