OSDN Git Service

[Refactor] #37353 player-skill.c/h を追加。
[hengband/hengband.git] / src / shoot.c
index e4045bc..8abb8c5 100644 (file)
@@ -1,8 +1,22 @@
 #include "angband.h"
-#include "projection.h"
+#include "util.h"
+
+#include "monster.h"
 #include "monster-status.h"
+#include "monster-spell.h"
 #include "artifact.h"
 #include "avatar.h"
+#include "player-status.h"
+#include "player-skill.h"
+#include "object-hook.h"
+#include "floor.h"
+#include "grid.h"
+#include "spells.h"
+#include "object-flavor.h"
+
+#include "shoot.h"
+#include "snipe.h"
+#include "view-mainwindow.h"
 
 /*!
  * @brief 矢弾を射撃した際のスレイ倍率をかけた結果を返す /
@@ -12,9 +26,9 @@
  * @param m_ptr 目標モンスターの構造体参照ポインタ
  * @return スレイ倍率をかけたダメージ量
  */
-static s16b tot_dam_aux_shot(object_type *o_ptr, int tdam, monster_type *m_ptr)
+static MULTIPLY tot_dam_aux_shot(object_type *o_ptr, HIT_POINT tdam, monster_type *m_ptr, SPELL_IDX snipe_type)
 {
-       int mult = 10;
+       MULTIPLY mult = 10;
 
        monster_race *r_ptr = &r_info[m_ptr->r_idx];
 
@@ -304,7 +318,7 @@ static s16b tot_dam_aux_shot(object_type *o_ptr, int tdam, monster_type *m_ptr)
        }
 
        /* Sniper */
-       if (snipe_type) mult = tot_dam_aux_snipe(mult, m_ptr);
+       if (snipe_type) mult = tot_dam_aux_snipe(mult, m_ptr, snipe_type);
 
        /* Return the total damage */
        return (tdam * mult / 10);
@@ -335,7 +349,7 @@ static s16b tot_dam_aux_shot(object_type *o_ptr, int tdam, monster_type *m_ptr)
  * Note that Bows of "Extra Shots" give an extra shot.
  * </pre>
  */
-void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
+void exe_fire(INVENTORY_IDX item, object_type *j_ptr, SPELL_IDX snipe_type)
 {
        DIRECTION dir;
        int i;
@@ -368,7 +382,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
        }
        else
        {
-               o_ptr = &o_list[0 - item];
+               o_ptr = &current_floor_ptr->o_list[0 - item];
        }
 
        /* Sniper - Cannot shot a single arrow twice */
@@ -419,7 +433,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
        /* Get a direction (or cancel) */
        if (!get_aim_dir(&dir))
        {
-               p_ptr->energy_use = 0;
+               free_turn(p_ptr);
 
                if (snipe_type == SP_AWAY) snipe_type = SP_NONE;
 
@@ -447,7 +461,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
        /* Don't shoot at my feet */
        if (tx == p_ptr->x && ty == p_ptr->y)
        {
-               p_ptr->energy_use = 0;
+               free_turn(p_ptr);
 
                /* project_length is already reset to 0 */
 
@@ -455,11 +469,11 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
        }
 
 
-       /* Take a (partial) turn */
+       /* Take a (partial) current_world_ptr->game_turn */
        p_ptr->energy_use = (p_ptr->energy_use / thits);
        is_fired = TRUE;
 
-       /* Sniper - Difficult to shot twice at 1 turn */
+       /* Sniper - Difficult to shot twice at 1 current_world_ptr->game_turn */
        if (snipe_type == SP_DOUBLE)  p_ptr->concent = (p_ptr->concent + 1) / 2;
 
        /* Sniper - Repeat shooting when double shots */
@@ -504,7 +518,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                /* Travel until stopped */
                for (cur_dis = 0; cur_dis <= tdis; )
                {
-                       cave_type *c_ptr;
+                       grid_type *g_ptr;
 
                        /* Hack -- Stop at the target */
                        if ((y == ty) && (x == tx)) break;
@@ -517,13 +531,13 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                        /* Shatter Arrow */
                        if (snipe_type == SP_KILL_WALL)
                        {
-                               c_ptr = &cave[ny][nx];
+                               g_ptr = &current_floor_ptr->grid_array[ny][nx];
 
-                               if (cave_have_flag_grid(c_ptr, FF_HURT_ROCK) && !c_ptr->m_idx)
+                               if (cave_have_flag_grid(g_ptr, FF_HURT_ROCK) && !g_ptr->m_idx)
                                {
-                                       if (c_ptr->info & (CAVE_MARK)) msg_print(_("岩が砕け散った。", "Wall rocks were shattered."));
+                                       if (g_ptr->info & (CAVE_MARK)) msg_print(_("岩が砕け散った。", "Wall rocks were shattered."));
                                        /* Forget the wall */
-                                       c_ptr->info &= ~(CAVE_MARK);
+                                       g_ptr->info &= ~(CAVE_MARK);
                                        p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE);
 
                                        /* Destroy the wall */
@@ -535,7 +549,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                        }
 
                        /* Stopped by walls/doors */
-                       if (!cave_have_flag_bold(ny, nx, FF_PROJECT) && !cave[ny][nx].m_idx) break;
+                       if (!cave_have_flag_bold(ny, nx, FF_PROJECT) && !current_floor_ptr->grid_array[ny][nx].m_idx) break;
 
                        /* Advance the distance */
                        cur_dis++;
@@ -543,7 +557,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                        /* Sniper */
                        if (snipe_type == SP_LITE)
                        {
-                               cave[ny][nx].info |= (CAVE_GLOW);
+                               current_floor_ptr->grid_array[ny][nx].info |= (CAVE_GLOW);
                                note_spot(ny, nx);
                                lite_spot(ny, nx);
                        }
@@ -580,7 +594,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                        /* Sniper */
                        if (snipe_type == SP_EVILNESS)
                        {
-                               cave[ny][nx].info &= ~(CAVE_GLOW | CAVE_MARK);
+                               current_floor_ptr->grid_array[ny][nx].info &= ~(CAVE_GLOW | CAVE_MARK);
                                note_spot(ny, nx);
                                lite_spot(ny, nx);
                        }
@@ -593,11 +607,11 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                        y = ny;
 
                        /* Monster here, Try to hit it */
-                       if (cave[y][x].m_idx)
+                       if (current_floor_ptr->grid_array[y][x].m_idx)
                        {
-                               cave_type *c_mon_ptr = &cave[y][x];
+                               grid_type *c_mon_ptr = &current_floor_ptr->grid_array[y][x];
 
-                               monster_type *m_ptr = &m_list[c_mon_ptr->m_idx];
+                               monster_type *m_ptr = &current_floor_ptr->m_list[c_mon_ptr->m_idx];
                                monster_race *r_ptr = &r_info[m_ptr->r_idx];
 
                                /* Check the visibility */
@@ -630,7 +644,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                                if (p_ptr->riding)
                                {
                                        if ((p_ptr->skill_exp[GINOU_RIDING] < s_info[p_ptr->pclass].s_max[GINOU_RIDING])
-                                               && ((p_ptr->skill_exp[GINOU_RIDING] - (RIDING_EXP_BEGINNER * 2)) / 200 < r_info[m_list[p_ptr->riding].r_idx].level)
+                                               && ((p_ptr->skill_exp[GINOU_RIDING] - (RIDING_EXP_BEGINNER * 2)) / 200 < r_info[current_floor_ptr->m_list[p_ptr->riding].r_idx].level)
                                                && one_in_(2))
                                        {
                                                p_ptr->skill_exp[GINOU_RIDING] += 1;
@@ -689,7 +703,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                                        else
                                        {
                                                /* Apply special damage */
-                                               tdam = tot_dam_aux_shot(q_ptr, tdam, m_ptr);
+                                               tdam = tot_dam_aux_shot(q_ptr, tdam, m_ptr, snipe_type);
                                                tdam = critical_shot(q_ptr->weight, q_ptr->to_h, j_ptr->to_h, tdam);
 
                                                /* No negative damage */
@@ -716,7 +730,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                                        /* Sniper */
                                        if (snipe_type == SP_HOLYNESS)
                                        {
-                                               cave[ny][nx].info |= (CAVE_GLOW);
+                                               current_floor_ptr->grid_array[ny][nx].info |= (CAVE_GLOW);
                                                note_spot(ny, nx);
                                                lite_spot(ny, nx);
                                        }
@@ -777,13 +791,13 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                                                                if (!in_bounds2(ny, nx)) break;
 
                                                                /* Stopped by walls/doors */
-                                                               if (!player_can_enter(cave[ny][nx].feat, 0)) break;
+                                                               if (!player_can_enter(current_floor_ptr->grid_array[ny][nx].feat, 0)) break;
 
                                                                /* Stopped by monsters */
                                                                if (!cave_empty_bold(ny, nx)) break;
 
-                                                               cave[ny][nx].m_idx = m_idx;
-                                                               cave[oy][ox].m_idx = 0;
+                                                               current_floor_ptr->grid_array[ny][nx].m_idx = m_idx;
+                                                               current_floor_ptr->grid_array[oy][ox].m_idx = 0;
 
                                                                m_ptr->fx = nx;
                                                                m_ptr->fy = ny;
@@ -819,12 +833,12 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                }
 
                /* Chance of breakage (during attacks) */
-               j = (hit_body ? breakage_chance(q_ptr) : 0);
+               j = (hit_body ? breakage_chance(q_ptr, snipe_type) : 0);
 
                if (stick_to)
                {
-                       MONSTER_IDX m_idx = cave[y][x].m_idx;
-                       monster_type *m_ptr = &m_list[m_idx];
+                       MONSTER_IDX m_idx = current_floor_ptr->grid_array[y][x].m_idx;
+                       monster_type *m_ptr = &current_floor_ptr->m_list[m_idx];
                        OBJECT_IDX o_idx = o_pop();
 
                        if (!o_idx)
@@ -837,7 +851,7 @@ void exe_fire(INVENTORY_IDX item, object_type *j_ptr)
                                return;
                        }
 
-                       o_ptr = &o_list[o_idx];
+                       o_ptr = &current_floor_ptr->o_list[o_idx];
                        object_copy(o_ptr, q_ptr);
 
                        /* Forget mark */
@@ -995,3 +1009,239 @@ HIT_POINT critical_shot(WEIGHT weight, int plus_ammo, int plus_bow, HIT_POINT da
 }
 
 
+
+
+/*!
+ * @brief 射撃武器の攻撃に必要な基本消費エネルギーを返す/Return bow energy
+ * @param sval 射撃武器のアイテム副分類ID
+ * @return 消費する基本エネルギー
+ */
+ENERGY bow_energy(OBJECT_SUBTYPE_VALUE sval)
+{
+       ENERGY energy = 10000;
+
+       /* Analyze the launcher */
+       switch (sval)
+       {
+               /* Sling and ammo */
+       case SV_SLING:
+       {
+               energy = 8000;
+               break;
+       }
+
+       /* Short Bow and Arrow */
+       case SV_SHORT_BOW:
+       {
+               energy = 10000;
+               break;
+       }
+
+       /* Long Bow and Arrow */
+       case SV_LONG_BOW:
+       {
+               energy = 10000;
+               break;
+       }
+
+       /* Bow of irresponsiblity and Arrow */
+       case SV_NAMAKE_BOW:
+       {
+               energy = 7777;
+               break;
+       }
+
+       /* Light Crossbow and Bolt */
+       case SV_LIGHT_XBOW:
+       {
+               energy = 12000;
+               break;
+       }
+
+       /* Heavy Crossbow and Bolt */
+       case SV_HEAVY_XBOW:
+       {
+               energy = 13333;
+               break;
+       }
+       }
+
+       return (energy);
+}
+
+
+/*
+ * Return bow tmul
+ */
+int bow_tmul(OBJECT_SUBTYPE_VALUE sval)
+{
+       int tmul = 0;
+
+       /* Analyze the launcher */
+       switch (sval)
+       {
+               /* Sling and ammo */
+       case SV_SLING:
+       {
+               tmul = 2;
+               break;
+       }
+
+       /* Short Bow and Arrow */
+       case SV_SHORT_BOW:
+       {
+               tmul = 2;
+               break;
+       }
+
+       /* Long Bow and Arrow */
+       case SV_LONG_BOW:
+       {
+               tmul = 3;
+               break;
+       }
+
+       /* Bow of irresponsiblity and Arrow */
+       case SV_NAMAKE_BOW:
+       {
+               tmul = 3;
+               break;
+       }
+
+       /* Light Crossbow and Bolt */
+       case SV_LIGHT_XBOW:
+       {
+               tmul = 3;
+               break;
+       }
+
+       /* Heavy Crossbow and Bolt */
+       case SV_HEAVY_XBOW:
+       {
+               tmul = 4;
+               break;
+       }
+       }
+
+       return (tmul);
+}
+
+
+/*!
+ * @brief 射撃時クリティカルによるダメージ期待値修正計算(スナイパーの集中処理と武器経験値) / critical happens at i / 10000
+ * @param plus_ammo 矢弾のダメージ修正
+ * @param plus_bow 弓のダメージ修正
+ * @return ダメージ期待値
+ * @note 基本ダメージ量と重量はこの部位では計算に加わらない。
+ */
+HIT_POINT calc_crit_ratio_shot(HIT_POINT plus_ammo, HIT_POINT plus_bow)
+{
+       HIT_POINT i;
+       object_type *j_ptr = &inventory[INVEN_BOW];
+
+       /* Extract "shot" power */
+       i = p_ptr->to_h_b + plus_ammo;
+
+       if (p_ptr->tval_ammo == TV_BOLT)
+               i = (p_ptr->skill_thb + (p_ptr->weapon_exp[0][j_ptr->sval] / 400 + i) * BTH_PLUS_ADJ);
+       else
+               i = (p_ptr->skill_thb + ((p_ptr->weapon_exp[0][j_ptr->sval] - (WEAPON_EXP_MASTER / 2)) / 200 + i) * BTH_PLUS_ADJ);
+
+       /* Snipers can shot more critically with crossbows */
+       if (p_ptr->concent) i += ((i * p_ptr->concent) / 5);
+       if ((p_ptr->pclass == CLASS_SNIPER) && (p_ptr->tval_ammo == TV_BOLT)) i *= 2;
+
+       /* Good bow makes more critical */
+       i += plus_bow * 8 * (p_ptr->concent ? p_ptr->concent + 5 : 5);
+
+       if (i < 0) i = 0;
+
+       return i;
+}
+
+/*!
+ * @brief 射撃時クリティカルによるダメージ期待値修正計算(重量依存部分) / critical happens at i / 10000
+ * @param weight 武器の重量
+ * @param plus_ammo 矢弾のダメージ修正
+ * @param plus_bow 弓のダメージ修正
+ * @param dam 基本ダメージ量
+ * @return ダメージ期待値
+ */
+HIT_POINT calc_expect_crit_shot(WEIGHT weight, int plus_ammo, int plus_bow, HIT_POINT dam)
+{
+       u32b num;
+       int i, k, crit;
+       i = calc_crit_ratio_shot(plus_ammo, plus_bow);
+
+       k = 0;
+       num = 0;
+
+       crit = MIN(500, 900 / weight);
+       num += dam * 3 / 2 * crit;
+       k = crit;
+
+       crit = MIN(500, 1350 / weight);
+       crit -= k;
+       num += dam * 2 * crit;
+       k += crit;
+
+       if (k < 500)
+       {
+               crit = 500 - k;
+               num += dam * 3 * crit;
+       }
+
+       num /= 500;
+
+       num *= i;
+       num += (10000 - i) * dam;
+       num /= 10000;
+
+       return num;
+}
+
+/*!
+ * @brief 攻撃時クリティカルによるダメージ期待値修正計算(重量と毒針処理) / critical happens at i / 10000
+ * @param weight 武器の重量
+ * @param plus 武器のダメージ修正
+ * @param dam 基本ダメージ
+ * @param meichuu 命中値
+ * @param dokubari 毒針処理か否か
+ * @return ダメージ期待値
+ */
+HIT_POINT calc_expect_crit(WEIGHT weight, int plus, HIT_POINT dam, s16b meichuu, bool dokubari)
+{
+       u32b k, num;
+       int i;
+
+       if (dokubari) return dam;
+
+       i = (weight + (meichuu * 3 + plus * 5) + p_ptr->skill_thn);
+       if (i < 0) i = 0;
+
+       k = weight;
+       num = 0;
+
+       if (k < 400)                                            num += (2 * dam + 5) * (400 - k);
+       if (k < 700)                                            num += (2 * dam + 10) * (MIN(700, k + 650) - MAX(400, k));
+       if (k > (700 - 650) && k < 900)         num += (3 * dam + 15) * (MIN(900, k + 650) - MAX(700, k));
+       if (k > (900 - 650) && k < 1300)                num += (3 * dam + 20) * (MIN(1300, k + 650) - MAX(900, k));
+       if (k > (1300 - 650))                                   num += (7 * dam / 2 + 25) * MIN(650, k - (1300 - 650));
+
+       num /= 650;
+       if (p_ptr->pclass == CLASS_NINJA)
+       {
+               num *= i;
+               num += (4444 - i) * dam;
+               num /= 4444;
+       }
+       else
+       {
+               num *= i;
+               num += (5000 - i) * dam;
+               num /= 5000;
+       }
+
+       return num;
+}
+