X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fmelee1.c;h=5eeeab2ba996ab91ddccc13051e413186c99a099;hb=b370729a5229fadc0a965cb6af7518d62a776c9b;hp=45d271a7d3e8c425d7d9c617ec68a0ff3157a05e;hpb=cba1032df6f3965c9ea8ad2ae061562348f4dad2;p=hengband%2Fhengband.git diff --git a/src/melee1.c b/src/melee1.c index 45d271a7d..5eeeab2ba 100644 --- a/src/melee1.c +++ b/src/melee1.c @@ -1,6 +1,6 @@ /*! * @file melee1.c - * @brief モンスターの打撃処理 / Monster attacks + * @brief 打撃処理 / Melee process. * @date 2014/01/17 * @author * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n @@ -12,20 +12,484 @@ */ #include "angband.h" +#include "core.h" +#include "util.h" + #include "artifact.h" #include "cmd-pet.h" -#include "player-damage.h" #include "monsterrace-hook.h" #include "melee.h" -#include "projection.h" +#include "monster.h" #include "monster-status.h" +#include "monster-spell.h" #include "avatar.h" -#include "player-status.h" #include "realm-hex.h" +#include "realm-song.h" +#include "object-flavor.h" #include "object-hook.h" #include "grid.h" +#include "dungeon.h" +#include "floor.h" +#include "dungeon.h" +#include "spells.h" +#include "files.h" +#include "player-move.h" +#include "player-effects.h" +#include "player-skill.h" +#include "player-damage.h" +#include "player-status.h" +#include "player-race.h" +#include "player-class.h" +#include "player-personality.h" +#include "view-mainwindow.h" +#include "world.h" +#include "spells-floor.h" + + + /*! + * @brief モンスターの打撃効力テーブル / + * The table of monsters' blow effects + */ +const mbe_info_type mbe_info[] = +{ + { 0, 0, }, /* None */ + { 60, GF_MISSILE, }, /* HURT */ + { 5, GF_POIS, }, /* POISON */ + { 20, GF_DISENCHANT, }, /* UN_BONUS */ + { 15, GF_MISSILE, }, /* UN_POWER */ /* ToDo: Apply the correct effects */ + { 5, GF_MISSILE, }, /* EAT_GOLD */ + { 5, GF_MISSILE, }, /* EAT_ITEM */ + { 5, GF_MISSILE, }, /* EAT_FOOD */ + { 5, GF_MISSILE, }, /* EAT_LITE */ + { 0, GF_ACID, }, /* ACID */ + { 10, GF_ELEC, }, /* ELEC */ + { 10, GF_FIRE, }, /* FIRE */ + { 10, GF_COLD, }, /* COLD */ + { 2, GF_MISSILE, }, /* BLIND */ + { 10, GF_CONFUSION, }, /* CONFUSE */ + { 10, GF_MISSILE, }, /* TERRIFY */ + { 2, GF_MISSILE, }, /* PARALYZE */ + { 0, GF_MISSILE, }, /* LOSE_STR */ + { 0, GF_MISSILE, }, /* LOSE_INT */ + { 0, GF_MISSILE, }, /* LOSE_WIS */ + { 0, GF_MISSILE, }, /* LOSE_DEX */ + { 0, GF_MISSILE, }, /* LOSE_CON */ + { 0, GF_MISSILE, }, /* LOSE_CHR */ + { 2, GF_MISSILE, }, /* LOSE_ALL */ + { 60, GF_ROCKET, }, /* SHATTER */ + { 5, GF_MISSILE, }, /* EXP_10 */ + { 5, GF_MISSILE, }, /* EXP_20 */ + { 5, GF_MISSILE, }, /* EXP_40 */ + { 5, GF_MISSILE, }, /* EXP_80 */ + { 5, GF_POIS, }, /* DISEASE */ + { 5, GF_TIME, }, /* TIME */ + { 5, GF_MISSILE, }, /* EXP_VAMP */ + { 5, GF_MANA, }, /* DR_MANA */ + { 60, GF_MISSILE, }, /* SUPERHURT */ +}; + + /*! + * @brief 幻覚時の打撃記述テーブル / Weird melee attack types when hallucinating + */ +#ifdef JP +const concptr silly_attacks[MAX_SILLY_ATTACK] = +{ + "に小便をかけられた。", + "があなたの回りを3回回ってワンと言った。", + "にしばきまわされた。", + "に靴をなめさせられた。", + "にハナクソを飛ばされた。", + "にジャン拳で攻撃された。", + "があなたの頬を札束でしばいた。", + "があなたの前でポージングをした。", + "にアカンベーされた。", + "に「神の国」発言の撤回を求められた。", + "にメッ○ールを飲まされた。", + "につっこみを入れられた。", + "はあなたと踊った。", + "に顔にらく書きをされた。", + "に借金の返済をせまられた。", + "にスカートをめくられた。", + "はあなたの手相を占った。", + "から役満を上がられた。", + "から愛の告白をされた。", + "はあなたを時給500円で雇った。", + "はあなたの100の秘密について熱く語った。", + "がニャーと鳴いた。", + "はあなたに気をつけた。", + "はあなたをポリゴン化させた。", + "に少しかじられた。", + "はアルテマの呪文を唱えた!", + "はあなたのスパイクをブロックした。", + "はスライド移動した。", + "は昇龍拳コマンドの入力に失敗した。", + "は拡散波動砲を発射した。", + "はデスラー戦法をしかけた。", + "にライダーキックで攻撃された。", + "に二週間以内でビデオを人に見せないと死ぬ呪いをかけられた。", + "はパルプンテを唱えた。", + "はスーパーウルトラギャラクティカマグナムを放った。", + "にしゃがみ小キックでハメられた。", + "にジェットストリームアタックをかけられた。", + "はあなたに卍固めをかけて「1、2、3、ダーッ!」と叫んだ。", + "は「いくじなし!ばかばかばか!」といって駆け出した。", + "が「ごらん、ルーベンスの絵だよ」と言って静かに目を閉じた。", + "は言った。「変愚蛮怒、絶賛公開中!」", +}; + +/*! + * @brief 幻覚時の打撃記述テーブル(フォーマットつき) / Weird melee attack types when hallucinating (%s for strfmt()) + */ +const concptr silly_attacks2[MAX_SILLY_ATTACK] = +{ + "%sに小便をかけた。", + "%sの回りを3回回ってワンと言った。", + "%sをしばきまわした。", + "%sに靴をなめさせた。", + "%sにハナクソを飛ばした。", + "%sをジャン拳で攻撃した。", + "%sの頬を札束でしばいた。", + "%sの前でポージングをした。", + "%sにアカンベーした。", + "%sに「神の国」発言の撤回を求めた。", + "%sにメッ○ールを飲ませた。", + "%sにつっこみを入れた。", + "%sと踊った。", + "%sの顔にらく書きをした。", + "%sに借金の返済をせまった。", + "%sのスカートをめくった。", + "%sの手相を占った。", + "%sから役満を上がった。", + "%sに愛の告白をした。", + "%sを時給500円で雇った。", + "%sの100の秘密について熱く語った。", + "ニャーと鳴いた。", + "%sに気をつけた。", + "%sをポリゴン化させた。", + "%sを少しかじった。", + "アルテマの呪文を唱えた!", + "%sのスパイクをブロックした。", + "スライド移動した。", + "昇龍拳コマンドの入力に失敗した。", + "%sに拡散波動砲を発射した。", + "%sにデスラー戦法をしかけた。", + "%sをライダーキックで攻撃した。", + "%sに二週間以内でビデオを人に見せないと死ぬ呪いをかけた。", + "パルプンテを唱えた。", + "%sにスーパーウルトラギャラクティカマグナムを放った。", + "%sをしゃがみ小キックでハメた。", + "%sにジェットストリームアタックをかけた。", + "%sに卍固めをかけて「1、2、3、ダーッ!」と叫んだ。", + "「いくじなし!ばかばかばか!」といって駆け出した。", + "「ごらん、ルーベンスの絵だよ」と言って静かに目を閉じた。", + "言った。「変愚蛮怒、絶賛公開中!」", +}; +#else +const concptr silly_attacks[MAX_SILLY_ATTACK] = +{ + "smothers", + "hugs", + "humiliates", + "whips", + "kisses", + + "disgusts", + "pees all over", + "passes the gas on", + "makes obscene gestures at", + "licks", + + "stomps on", + "swallows", + "drools on", + "misses", + "shrinks", + + "emasculates", + "evaporates", + "solidifies", + "digitizes", + "insta-kills", + + "massacres", + "slaughters", + "drugs", + "psychoanalyzes", + "deconstructs", + + "falsifies", + "disbelieves", + "molests", + "pusupusu", +}; +#endif + + + +/*! + * @brief マーシャルアーツ打撃テーブル + */ +const martial_arts ma_blows[MAX_MA] = +{ +#ifdef JP + { "%sを殴った。", 1, 0, 1, 5, 0 }, + { "%sを蹴った。", 2, 0, 1, 7, 0 }, + { "%sに正拳突きをくらわした。", 3, 0, 1, 9, 0 }, + { "%sに膝蹴りをくらわした。", 5, 5, 2, 4, MA_KNEE }, + { "%sに肘打ちをくらわした。", 7, 5, 1, 12, 0 }, + { "%sに体当りした。", 9, 10, 2, 6, 0 }, + { "%sを蹴った。", 11, 10, 3, 6, MA_SLOW }, + { "%sにアッパーをくらわした。", 13, 12, 5, 5, 6 }, + { "%sに二段蹴りをくらわした。", 16, 15, 5, 6, 8 }, + { "%sに猫爪撃をくらわした。", 20, 20, 5, 8, 0 }, + { "%sに跳空脚をくらわした。", 24, 25, 6, 8, 10 }, + { "%sに鷲爪襲をくらわした。", 28, 25, 7, 9, 0 }, + { "%sに回し蹴りをくらわした。", 32, 30, 8, 10, 10 }, + { "%sに鉄拳撃をくらわした。", 35, 35, 8, 11, 10 }, + { "%sに飛空脚をくらわした。", 39, 35, 8, 12, 12 }, + { "%sに昇龍拳をくらわした。", 43, 35, 9, 12, 16 }, + { "%sに石破天驚拳をくらわした。", 48, 40, 10, 13, 18 }, +#else + { "You punch %s.", 1, 0, 1, 4, 0 }, + { "You kick %s.", 2, 0, 1, 6, 0 }, + { "You strike %s.", 3, 0, 1, 7, 0 }, + { "You hit %s with your knee.", 5, 5, 2, 3, MA_KNEE }, + { "You hit %s with your elbow.", 7, 5, 1, 8, 0 }, + { "You butt %s.", 9, 10, 2, 5, 0 }, + { "You kick %s.", 11, 10, 3, 4, MA_SLOW }, + { "You uppercut %s.", 13, 12, 4, 4, 6 }, + { "You double-kick %s.", 16, 15, 5, 4, 8 }, + { "You hit %s with a Cat's Claw.", 20, 20, 5, 5, 0 }, + { "You hit %s with a jump kick.", 25, 25, 5, 6, 10 }, + { "You hit %s with an Eagle's Claw.", 29, 25, 6, 6, 0 }, + { "You hit %s with a circle kick.", 33, 30, 6, 8, 10 }, + { "You hit %s with an Iron Fist.", 37, 35, 8, 8, 10 }, + { "You hit %s with a flying kick.", 41, 35, 8, 10, 12 }, + { "You hit %s with a Dragon Fist.", 45, 35, 10, 10, 16 }, + { "You hit %s with a Crushing Blow.", 48, 35, 10, 12, 18 }, +#endif + +}; + +/*! + * @brief 修行僧のターンダメージ算出テーブル + */ +const int monk_ave_damage[PY_MAX_LEVEL + 1][3] = +{ + {0, 0, 0}, + {249, 249, 249}, + {324, 324, 324}, + {382, 438, 382}, + {382, 439, 382}, + {390, 446, 390}, + {394, 473, 394}, + {425, 528, 425}, + {430, 535, 430}, + {505, 560, 435}, + {517, 575, 444}, + {566, 655, 474}, + {585, 713, 486}, + {653, 843, 527}, + {678, 890, 544}, + {703, 973, 558}, + {765, 1096, 596}, + {914, 1146, 614}, + {943, 1240, 629}, + {971, 1276, 643}, + {1018, 1350, 667}, + {1063, 1464, 688}, + {1099, 1515, 705}, + {1128, 1559, 721}, + {1153, 1640, 735}, + {1336, 1720, 757}, + {1387, 1789, 778}, + {1430, 1893, 794}, + {1610, 2199, 863}, + {1666, 2280, 885}, + {1713, 2401, 908}, + {1755, 2465, 925}, + {1909, 2730, 984}, + {2156, 2891, 1009}, + {2218, 2970, 1031}, + {2319, 3107, 1063}, + {2404, 3290, 1098}, + {2477, 3389, 1125}, + {2544, 3483, 1150}, + {2771, 3899, 1228}, + {2844, 3982, 1259}, + {3129, 4064, 1287}, + {3200, 4190, 1313}, + {3554, 4674, 1432}, + {3614, 4738, 1463}, + {3679, 4853, 1485}, + {3741, 4905, 1512}, + {3785, 4943, 1538}, + {4141, 5532, 1652}, + {4442, 5581, 1679}, + {4486, 5636, 1702}, +}; + +/*! + * 腕力による攻撃回数算定値テーブル + * Stat Table (STR) -- help index into the "blow" table + */ +const byte adj_str_blow[] = +{ + 3 /* 3 */, + 4 /* 4 */, + 5 /* 5 */, + 6 /* 6 */, + 7 /* 7 */, + 8 /* 8 */, + 9 /* 9 */, + 10 /* 10 */, + 11 /* 11 */, + 12 /* 12 */, + 13 /* 13 */, + 14 /* 14 */, + 15 /* 15 */, + 16 /* 16 */, + 17 /* 17 */, + 20 /* 18/00-18/09 */, + 30 /* 18/10-18/19 */, + 40 /* 18/20-18/29 */, + 50 /* 18/30-18/39 */, + 60 /* 18/40-18/49 */, + 70 /* 18/50-18/59 */, + 80 /* 18/60-18/69 */, + 90 /* 18/70-18/79 */, + 100 /* 18/80-18/89 */, + 110 /* 18/90-18/99 */, + 120 /* 18/100-18/109 */, + 130 /* 18/110-18/119 */, + 140 /* 18/120-18/129 */, + 150 /* 18/130-18/139 */, + 160 /* 18/140-18/149 */, + 170 /* 18/150-18/159 */, + 180 /* 18/160-18/169 */, + 190 /* 18/170-18/179 */, + 200 /* 18/180-18/189 */, + 210 /* 18/190-18/199 */, + 220 /* 18/200-18/209 */, + 230 /* 18/210-18/219 */, + 240 /* 18/220+ */ +}; + + +/*! + * 器用さによる攻撃回数インデックステーブル + * Stat Table (DEX) -- index into the "blow" table + */ +const byte adj_dex_blow[] = +{ + 0 /* 3 */, + 0 /* 4 */, + 0 /* 5 */, + 0 /* 6 */, + 0 /* 7 */, + 0 /* 8 */, + 0 /* 9 */, + 1 /* 10 */, + 1 /* 11 */, + 1 /* 12 */, + 1 /* 13 */, + 1 /* 14 */, + 2 /* 15 */, + 2 /* 16 */, + 2 /* 17 */, + 2 /* 18/00-18/09 */, + 3 /* 18/10-18/19 */, + 3 /* 18/20-18/29 */, + 3 /* 18/30-18/39 */, + 4 /* 18/40-18/49 */, + 4 /* 18/50-18/59 */, + 5 /* 18/60-18/69 */, + 5 /* 18/70-18/79 */, + 6 /* 18/80-18/89 */, + 6 /* 18/90-18/99 */, + 7 /* 18/100-18/109 */, + 7 /* 18/110-18/119 */, + 8 /* 18/120-18/129 */, + 8 /* 18/130-18/139 */, + 9 /* 18/140-18/149 */, + 9 /* 18/150-18/159 */, + 10 /* 18/160-18/169 */, + 10 /* 18/170-18/179 */, + 11 /* 18/180-18/189 */, + 11 /* 18/190-18/199 */, + 12 /* 18/200-18/209 */, + 12 /* 18/210-18/219 */, + 13 /* 18/220+ */ +}; +/*! + * @brief + * 腕力、器用さに応じた攻撃回数テーブル / + * This table is used to help calculate the number of blows the player can + * make in a single round of attacks (one player current_world_ptr->game_turn) with a normal weapon. + * @details + *
+ * This number ranges from a single blow/round for weak players to up to six
+ * blows/round for powerful warriors.
+ *
+ * Note that certain artifacts and ego-items give "bonus" blows/round.
+ *
+ * First, from the player class, we extract some values:
+ *
+ * Warrior       num = 6; mul = 5; div = MAX(70, weapon_weight);
+ * Berserker     num = 6; mul = 7; div = MAX(70, weapon_weight);
+ * Mage          num = 3; mul = 2; div = MAX(100, weapon_weight);
+ * Priest        num = 5; mul = 3; div = MAX(100, weapon_weight);
+ * Mindcrafter   num = 5; mul = 3; div = MAX(100, weapon_weight);
+ * Rogue         num = 5; mul = 3; div = MAX(40, weapon_weight);
+ * Ranger        num = 5; mul = 4; div = MAX(70, weapon_weight);
+ * Paladin       num = 5; mul = 4; div = MAX(70, weapon_weight);
+ * Weaponsmith   num = 5; mul = 5; div = MAX(150, weapon_weight);
+ * Warrior-Mage  num = 5; mul = 3; div = MAX(70, weapon_weight);
+ * Chaos Warrior num = 5; mul = 4; div = MAX(70, weapon_weight);
+ * Monk          num = 5; mul = 3; div = MAX(60, weapon_weight);
+ * Tourist       num = 4; mul = 3; div = MAX(100, weapon_weight);
+ * Imitator      num = 5; mul = 4; div = MAX(70, weapon_weight);
+ * Beastmaster   num = 5; mul = 3; div = MAX(70, weapon_weight);
+ * Cavalry(Ride) num = 5; mul = 4; div = MAX(70, weapon_weight);
+ * Cavalry(Walk) num = 5; mul = 3; div = MAX(100, weapon_weight);
+ * Sorcerer      num = 1; mul = 1; div = MAX(1, weapon_weight);
+ * Archer        num = 4; mul = 2; div = MAX(70, weapon_weight);
+ * Magic eater   num = 4; mul = 2; div = MAX(70, weapon_weight);
+ * ForceTrainer  num = 4; mul = 2; div = MAX(60, weapon_weight);
+ * Mirror Master num = 3; mul = 3; div = MAX(100, weapon_weight);
+ * Ninja         num = 4; mul = 1; div = MAX(20, weapon_weight);
+ *
+ * To get "P", we look up the relevant "adj_str_blow[]" (see above),
+ * multiply it by "mul", and then divide it by "div".
+ * Increase P by 1 if you wield a weapon two-handed.
+ * Decrease P by 1 if you are a Ninja.
+ *
+ * To get "D", we look up the relevant "adj_dex_blow[]" (see above),
+ *
+ * The player gets "blows_table[P][D]" blows/round, as shown below,
+ * up to a maximum of "num" blows/round, plus any "bonus" blows/round.
+ * 
+ */ +const byte blows_table[12][12] = +{ + /* P/D */ + /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11+ */ + /* 3 10 15 /10 /40 /60 /80 /100 /120 /140 /160 /180 */ + /* 0 */{ 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4 }, + /* 1 */{ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 }, + /* 2 */{ 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5 }, + /* 3 */{ 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5 }, + /* 4 */{ 1, 1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5 }, + /* 5 */{ 1, 1, 2, 3, 4, 4, 4, 5, 5, 5, 5, 6 }, + /* 6 */{ 1, 1, 2, 3, 4, 4, 4, 5, 5, 5, 5, 6 }, + /* 7 */{ 1, 2, 2, 3, 4, 4, 4, 5, 5, 5, 5, 6 }, + /* 8 */{ 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6 }, + /* 9 */{ 1, 2, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6 }, + /* 10*/{ 2, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6 }, + /*11+*/{ 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6 }, +}; /*! * @brief プレイヤーからモンスターへの打撃命中判定 / @@ -51,14 +515,391 @@ bool test_hit_norm(HIT_RELIABILITY chance, ARMOUR_CLASS ac, bool visible) PERCENTAGE hit_chance(HIT_RELIABILITY reli, ARMOUR_CLASS ac) { PERCENTAGE chance = 5, chance_left = 90; - if (reli <= 0) return 5; - if (p_ptr->pseikaku == SEIKAKU_NAMAKE) chance_left = (chance_left * 19 + 9) / 20; + if(reli <= 0) return 5; + if(p_ptr->pseikaku == SEIKAKU_NAMAKE) chance_left = (chance_left * 19 + 9) / 20; chance += (100 - ((ac * 75) / reli)) * chance_left / 100; - + if (chance < 5) chance = 5; return chance; } +/*! + * @brief プレイヤー攻撃の種族スレイング倍率計算 + * @param mult 算出前の基本倍率(/10倍) + * @param flgs スレイフラグ配列 + * @param m_ptr 目標モンスターの構造体参照ポインタ + * @return スレイング加味後の倍率(/10倍) + */ +static MULTIPLY mult_slaying(MULTIPLY mult, const BIT_FLAGS* flgs, const monster_type* m_ptr) +{ + static const struct slay_table_t { + int slay_flag; + BIT_FLAGS affect_race_flag; + MULTIPLY slay_mult; + size_t flag_offset; + size_t r_flag_offset; + } slay_table[] = { +#define OFFSET(X) offsetof(monster_race, X) + {TR_SLAY_ANIMAL, RF3_ANIMAL, 25, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_ANIMAL, RF3_ANIMAL, 40, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_EVIL, RF3_EVIL, 20, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_EVIL, RF3_EVIL, 35, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_GOOD, RF3_GOOD, 20, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_GOOD, RF3_GOOD, 35, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_HUMAN, RF2_HUMAN, 25, OFFSET(flags2), OFFSET(r_flags2)}, + {TR_KILL_HUMAN, RF2_HUMAN, 40, OFFSET(flags2), OFFSET(r_flags2)}, + {TR_SLAY_UNDEAD, RF3_UNDEAD, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_UNDEAD, RF3_UNDEAD, 50, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_DEMON, RF3_DEMON, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_DEMON, RF3_DEMON, 50, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_ORC, RF3_ORC, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_ORC, RF3_ORC, 50, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_TROLL, RF3_TROLL, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_TROLL, RF3_TROLL, 50, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_GIANT, RF3_GIANT, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_GIANT, RF3_GIANT, 50, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_SLAY_DRAGON, RF3_DRAGON, 30, OFFSET(flags3), OFFSET(r_flags3)}, + {TR_KILL_DRAGON, RF3_DRAGON, 50, OFFSET(flags3), OFFSET(r_flags3)}, +#undef OFFSET + }; + int i; + monster_race* r_ptr = &r_info[m_ptr->r_idx]; + + for (i = 0; i < sizeof(slay_table) / sizeof(slay_table[0]); ++i) + { + const struct slay_table_t* p = &slay_table[i]; + + if ((have_flag(flgs, p->slay_flag)) && + (atoffset(BIT_FLAGS, r_ptr, p->flag_offset) & p->affect_race_flag)) + { + if (is_original_ap_and_seen(m_ptr)) + { + atoffset(BIT_FLAGS, r_ptr, p->r_flag_offset) |= p->affect_race_flag; + } + + mult = MAX(mult, p->slay_mult); + } + } + + return mult; +} + +/*! + * @brief プレイヤー攻撃の属性スレイング倍率計算 + * @param mult 算出前の基本倍率(/10倍) + * @param flgs スレイフラグ配列 + * @param m_ptr 目標モンスターの構造体参照ポインタ + * @return スレイング加味後の倍率(/10倍) + */ +static MULTIPLY mult_brand(MULTIPLY mult, const BIT_FLAGS* flgs, const monster_type* m_ptr) +{ + static const struct brand_table_t { + int brand_flag; + BIT_FLAGS resist_mask; + BIT_FLAGS hurt_flag; + } brand_table[] = { + {TR_BRAND_ACID, RFR_EFF_IM_ACID_MASK, 0U }, + {TR_BRAND_ELEC, RFR_EFF_IM_ELEC_MASK, 0U }, + {TR_BRAND_FIRE, RFR_EFF_IM_FIRE_MASK, RF3_HURT_FIRE}, + {TR_BRAND_COLD, RFR_EFF_IM_COLD_MASK, RF3_HURT_COLD}, + {TR_BRAND_POIS, RFR_EFF_IM_POIS_MASK, 0U }, + }; + int i; + monster_race* r_ptr = &r_info[m_ptr->r_idx]; + + for (i = 0; i < sizeof(brand_table) / sizeof(brand_table[0]); ++i) + { + const struct brand_table_t* p = &brand_table[i]; + + if (have_flag(flgs, p->brand_flag)) + { + /* Notice immunity */ + if (r_ptr->flagsr & p->resist_mask) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flagsr |= (r_ptr->flagsr & p->resist_mask); + } + } + + /* Otherwise, take the damage */ + else if (r_ptr->flags3 & p->hurt_flag) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= p->hurt_flag; + } + + mult = MAX(mult, 50); + } + else + { + mult = MAX(mult, 25); + } + } + } + + return mult; +} + +/*! + * @brief 剣術のスレイ倍率計算を行う / + * Calcurate magnification of hissatsu technics + * @param mult 剣術のスレイ効果以前に算出している多要素の倍率(/10倍) + * @param flgs 剣術に使用する武器のスレイフラグ配列 + * @param m_ptr 目標となるモンスターの構造体参照ポインタ + * @param mode 剣術のスレイ型ID + * @return スレイの倍率(/10倍) + */ +static MULTIPLY mult_hissatsu(MULTIPLY mult, BIT_FLAGS *flgs, monster_type *m_ptr, BIT_FLAGS mode) +{ + monster_race *r_ptr = &r_info[m_ptr->r_idx]; + + /* Burning Strike (Fire) */ + if (mode == HISSATSU_FIRE) + { + /* Notice immunity */ + if (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK); + } + } + + /* Otherwise, take the damage */ + else if (have_flag(flgs, TR_BRAND_FIRE)) + { + if (r_ptr->flags3 & RF3_HURT_FIRE) + { + if (mult < 70) mult = 70; + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_HURT_FIRE; + } + } + else if (mult < 35) mult = 35; + } + else + { + if (r_ptr->flags3 & RF3_HURT_FIRE) + { + if (mult < 50) mult = 50; + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_HURT_FIRE; + } + } + else if (mult < 25) mult = 25; + } + } + + /* Serpent's Tongue (Poison) */ + if (mode == HISSATSU_POISON) + { + /* Notice immunity */ + if (r_ptr->flagsr & RFR_EFF_IM_POIS_MASK) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_POIS_MASK); + } + } + + /* Otherwise, take the damage */ + else if (have_flag(flgs, TR_BRAND_POIS)) + { + if (mult < 35) mult = 35; + } + else + { + if (mult < 25) mult = 25; + } + } + + /* Zammaken (Nonliving Evil) */ + if (mode == HISSATSU_ZANMA) + { + if (!monster_living(m_ptr->r_idx) && (r_ptr->flags3 & RF3_EVIL)) + { + if (mult < 15) mult = 25; + else if (mult < 50) mult = MIN(50, mult + 20); + } + } + + /* Rock Smash (Hurt Rock) */ + if (mode == HISSATSU_HAGAN) + { + if (r_ptr->flags3 & RF3_HURT_ROCK) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_HURT_ROCK; + } + if (mult == 10) mult = 40; + else if (mult < 60) mult = 60; + } + } + + /* Midare-Setsugekka (Cold) */ + if (mode == HISSATSU_COLD) + { + /* Notice immunity */ + if (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK); + } + } + /* Otherwise, take the damage */ + else if (have_flag(flgs, TR_BRAND_COLD)) + { + if (r_ptr->flags3 & RF3_HURT_COLD) + { + if (mult < 70) mult = 70; + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_HURT_COLD; + } + } + else if (mult < 35) mult = 35; + } + else + { + if (r_ptr->flags3 & RF3_HURT_COLD) + { + if (mult < 50) mult = 50; + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_HURT_COLD; + } + } + else if (mult < 25) mult = 25; + } + } + + /* Lightning Eagle (Elec) */ + if (mode == HISSATSU_ELEC) + { + /* Notice immunity */ + if (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK); + } + } + + /* Otherwise, take the damage */ + else if (have_flag(flgs, TR_BRAND_ELEC)) + { + if (mult < 70) mult = 70; + } + else + { + if (mult < 50) mult = 50; + } + } + + /* Bloody Maelstrom */ + if ((mode == HISSATSU_SEKIRYUKA) && p_ptr->cut && monster_living(m_ptr->r_idx)) + { + MULTIPLY tmp = MIN(100, MAX(10, p_ptr->cut / 10)); + if (mult < tmp) mult = tmp; + } + + /* Keiun-Kininken */ + if (mode == HISSATSU_UNDEAD) + { + if (r_ptr->flags3 & RF3_UNDEAD) + { + if (is_original_ap_and_seen(m_ptr)) + { + r_ptr->r_flags3 |= RF3_UNDEAD; + } + if (mult == 10) mult = 70; + else if (mult < 140) mult = MIN(140, mult + 60); + } + if (mult == 10) mult = 40; + else if (mult < 60) mult = MIN(60, mult + 30); + } + + if (mult > 150) mult = 150; + + return mult; +} + +/*! + * @brief ダメージにスレイ要素を加える総合処理ルーチン / + * Extract the "total damage" from a given object hitting a given monster. + * @param o_ptr 使用武器オブジェクトの構造体参照ポインタ + * @param tdam 現在算出途中のダメージ値 + * @param m_ptr 目標モンスターの構造体参照ポインタ + * @param mode 剣術のID + * @param thrown 投擲処理ならばTRUEを指定する + * @return 総合的なスレイを加味したダメージ値 + * @note + * Note that "flasks of oil" do NOT do fire damage, although they\n + * certainly could be made to do so. XXX XXX\n + *\n + * Note that most brands and slays are x3, except Slay Animal (x2),\n + * Slay Evil (x2), and Kill dragon (x5).\n + */ +HIT_POINT tot_dam_aux(object_type *o_ptr, HIT_POINT tdam, monster_type *m_ptr, BIT_FLAGS mode, bool thrown) +{ + MULTIPLY mult = 10; + + BIT_FLAGS flgs[TR_FLAG_SIZE]; + object_flags(o_ptr, flgs); + torch_flags(o_ptr, flgs); /* torches has secret flags */ + + if (!thrown) + { + if (p_ptr->special_attack & (ATTACK_ACID)) add_flag(flgs, TR_BRAND_ACID); + if (p_ptr->special_attack & (ATTACK_COLD)) add_flag(flgs, TR_BRAND_COLD); + if (p_ptr->special_attack & (ATTACK_ELEC)) add_flag(flgs, TR_BRAND_ELEC); + if (p_ptr->special_attack & (ATTACK_FIRE)) add_flag(flgs, TR_BRAND_FIRE); + if (p_ptr->special_attack & (ATTACK_POIS)) add_flag(flgs, TR_BRAND_POIS); + } + + if (hex_spelling(HEX_RUNESWORD)) add_flag(flgs, TR_SLAY_GOOD); + + switch (o_ptr->tval) + { + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + case TV_HAFTED: + case TV_POLEARM: + case TV_SWORD: + case TV_DIGGING: + case TV_LITE: + { + mult = mult_slaying(mult, flgs, m_ptr); + + mult = mult_brand(mult, flgs, m_ptr); + + if (p_ptr->pclass == CLASS_SAMURAI) + { + mult = mult_hissatsu(mult, flgs, m_ptr, mode); + } + + if ((p_ptr->pclass != CLASS_SAMURAI) && (have_flag(flgs, TR_FORCE_WEAPON)) && (p_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) + { + p_ptr->csp -= (1 + (o_ptr->dd * o_ptr->ds / 5)); + p_ptr->redraw |= (PR_MANA); + mult = mult * 3 / 2 + 20; + } + + if ((o_ptr->name1 == ART_NOTHUNG) && (m_ptr->r_idx == MON_FAFNER)) + mult = 150; + break; + } + } + if (mult > 150) mult = 150; + return (tdam * mult / 10); +} /*! * @brief プレイヤーからモンスターへの打撃クリティカル判定 / @@ -168,25 +1009,36 @@ static int check_hit(int power, DEPTH level, int stun) { int i, k, ac; - /* Percentile dice */ k = randint0(100); - if (stun && one_in_(2)) return FALSE; - - /* Hack -- Always miss or hit */ if (k < 10) return (k < 5); - - /* Calculate the "attack quality" */ i = (power + (level * 3)); - /* Total armor */ ac = p_ptr->ac + p_ptr->to_a; if (p_ptr->special_attack & ATTACK_SUIKEN) ac += (p_ptr->lev * 2); - /* Power and Level compete against Armor */ if ((i > 0) && (randint1(i) > ((ac * 3) / 4))) return (TRUE); + return (FALSE); +} + +/*! + * @brief モンスターから敵モンスターへの命中判定 + * @param power 打撃属性による基本命中値 + * @param level 攻撃側モンスターのレベル + * @param ac 目標モンスターのAC + * @param stun 攻撃側モンスターが朦朧状態ならTRUEを返す + * @return 命中ならばTRUEを返す + */ +static int check_hit2(int power, DEPTH level, ARMOUR_CLASS ac, int stun) +{ + int i, k; + + k = randint0(100); + if (stun && one_in_(2)) return FALSE; + if (k < 10) return (k < 5); + i = (power + (level * 3)); - /* Assume miss */ + if ((i > 0) && (randint1(i) > ((ac * 3) / 4))) return (TRUE); return (FALSE); } @@ -252,21 +1104,18 @@ static void touch_zap_player_aux(monster_type *m_ptr, bool immune, int flags_off { monster_race *r_ptr = &r_info[m_ptr->r_idx]; - if ((atoffset(u32b, r_ptr, flags_offset) & aura_flag) && !immune) + if ((atoffset(BIT_FLAGS, r_ptr, flags_offset) & aura_flag) && !immune) { GAME_TEXT mon_name[MAX_NLEN]; int aura_damage = damroll(1 + (r_ptr->level / 26), 1 + (r_ptr->level / 17)); - /* Hack -- Get the "died from" name */ - monster_desc(mon_name, m_ptr, MD_IGNORE_HALLU | MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE); - + monster_desc(mon_name, m_ptr, MD_WRONGDOER_NAME); msg_print(message); - dam_func(aura_damage, mon_name, -1, TRUE); if (is_original_ap_and_seen(m_ptr)) { - atoffset(u32b, r_ptr, r_flags_offset) |= aura_flag; + atoffset(BIT_FLAGS, r_ptr, r_flags_offset) |= aura_flag; } handle_stuff(); @@ -301,7 +1150,7 @@ static void natural_attack(MONSTER_IDX m_idx, int attack, bool *fear, bool *mdea HIT_POINT k; int bonus, chance; WEIGHT n_weight = 0; - monster_type *m_ptr = &m_list[m_idx]; + monster_type *m_ptr = ¤t_floor_ptr->m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; GAME_TEXT m_name[MAX_NLEN]; @@ -352,7 +1201,6 @@ static void natural_attack(MONSTER_IDX m_idx, int attack, bool *fear, bool *mdea } - /* Extract monster name (or "it") */ monster_desc(m_name, m_ptr, 0); /* Calculate the "attack quality" */ @@ -431,18 +1279,18 @@ static void natural_attack(MONSTER_IDX m_idx, int attack, bool *fear, bool *mdea * @details * If no "weapon" is available, then "punch" the monster one time. */ -static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b hand, BIT_FLAGS mode) +static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b hand, COMBAT_OPTION_IDX mode) { int num = 0, bonus, chance, vir; HIT_POINT k; - grid_type *g_ptr = ¤t_floor->grid_array[y][x]; + grid_type *g_ptr = ¤t_floor_ptr->grid_array[y][x]; - monster_type *m_ptr = &m_list[g_ptr->m_idx]; + monster_type *m_ptr = ¤t_floor_ptr->m_list[g_ptr->m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Access the weapon */ - object_type *o_ptr = &inventory[INVEN_RARM + hand]; + object_type *o_ptr = &p_ptr->inventory_list[INVEN_RARM + hand]; GAME_TEXT m_name[MAX_NLEN]; @@ -520,8 +1368,8 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b { if ((r_ptr->level + 10) > p_ptr->lev) { - OBJECT_TYPE_VALUE tval = inventory[INVEN_RARM + hand].tval - TV_WEAPON_BEGIN; - OBJECT_SUBTYPE_VALUE sval = inventory[INVEN_RARM + hand].sval; + OBJECT_TYPE_VALUE tval = p_ptr->inventory_list[INVEN_RARM + hand].tval - TV_WEAPON_BEGIN; + OBJECT_SUBTYPE_VALUE sval = p_ptr->inventory_list[INVEN_RARM + hand].sval; int now_exp = p_ptr->weapon_exp[tval][sval]; if (now_exp < s_info[p_ptr->pclass].w_max[tval][sval]) { @@ -539,7 +1387,6 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b /* Disturb the monster */ (void)set_monster_csleep(g_ptr->m_idx, 0); - /* Extract monster name (or "it") */ monster_desc(m_name, m_ptr, 0); /* Calculate the "attack quality" */ @@ -613,7 +1460,7 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b if ((have_flag(flgs, TR_CHAOTIC)) && one_in_(2)) { if (one_in_(10)) - chg_virtue(V_CHANCE, 1); + chg_virtue(p_ptr, V_CHANCE, 1); if (randint1(5) < 3) { @@ -1061,9 +1908,9 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b drain_msg = FALSE; } - drain_heal = (drain_heal * mutant_regenerate_mod) / 100; + drain_heal = (drain_heal * p_ptr->mutant_regenerate_mod) / 100; - hp_player(drain_heal); + hp_player(p_ptr, drain_heal); /* We get to keep some of it! */ } } @@ -1152,7 +1999,7 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b } /* Hack -- Get new monster */ - m_ptr = &m_list[g_ptr->m_idx]; + m_ptr = ¤t_floor_ptr->m_list[g_ptr->m_idx]; /* Oops, we need a different name... */ monster_desc(m_name, m_ptr, 0); @@ -1163,11 +2010,11 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b } else if (o_ptr->name1 == ART_G_HAMMER) { - monster_type *target_ptr = &m_list[g_ptr->m_idx]; + monster_type *target_ptr = ¤t_floor_ptr->m_list[g_ptr->m_idx]; if (target_ptr->hold_o_idx) { - object_type *q_ptr = &o_list[target_ptr->hold_o_idx]; + object_type *q_ptr = ¤t_floor_ptr->o_list[target_ptr->hold_o_idx]; GAME_TEXT o_name[MAX_NLEN]; object_desc(o_name, q_ptr, OD_NAME_ONLY); @@ -1300,14 +2147,14 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b { if (one_in_(4)) { - chg_virtue(V_UNLIFE, 1); + chg_virtue(p_ptr, V_UNLIFE, 1); } } /* Mega-Hack -- apply earthquake brand */ if (do_quake) { - earthquake(p_ptr->y, p_ptr->x, 10); - if (!current_floor->grid_array[y][x].m_idx) *mdeath = TRUE; + earthquake(p_ptr->y, p_ptr->x, 10, 0); + if (!current_floor_ptr->grid_array[y][x].m_idx) *mdeath = TRUE; } } @@ -1320,14 +2167,14 @@ static void py_attack_aux(POSITION y, POSITION x, bool *fear, bool *mdeath, s16b * @details * If no "weapon" is available, then "punch" the monster one time. */ -bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) +bool py_attack(POSITION y, POSITION x, COMBAT_OPTION_IDX mode) { bool fear = FALSE; bool mdeath = FALSE; bool stormbringer = FALSE; - grid_type *g_ptr = ¤t_floor->grid_array[y][x]; - monster_type *m_ptr = &m_list[g_ptr->m_idx]; + grid_type *g_ptr = ¤t_floor_ptr->grid_array[y][x]; + monster_type *m_ptr = ¤t_floor_ptr->m_list[g_ptr->m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; GAME_TEXT m_name[MAX_NLEN]; @@ -1343,7 +2190,6 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) return FALSE; } - /* Extract monster name (or "it") */ monster_desc(m_name, m_ptr, 0); if (m_ptr->ml) @@ -1351,14 +2197,13 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) /* Auto-Recall if possible and visible */ if (!p_ptr->image) monster_race_track(m_ptr->ap_r_idx); - /* Track a new monster */ health_track(g_ptr->m_idx); } if ((r_ptr->flags1 & RF1_FEMALE) && !(p_ptr->stun || p_ptr->confused || p_ptr->image || !m_ptr->ml)) { - if ((inventory[INVEN_RARM].name1 == ART_ZANTETSU) || (inventory[INVEN_LARM].name1 == ART_ZANTETSU)) + if ((p_ptr->inventory_list[INVEN_RARM].name1 == ART_ZANTETSU) || (p_ptr->inventory_list[INVEN_LARM].name1 == ART_ZANTETSU)) { msg_print(_("拙者、おなごは斬れぬ!", "I can not attack women!")); return FALSE; @@ -1376,24 +2221,24 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) !(p_ptr->stun || p_ptr->confused || p_ptr->image || p_ptr->shero || !m_ptr->ml)) { - if (inventory[INVEN_RARM].name1 == ART_STORMBRINGER) stormbringer = TRUE; - if (inventory[INVEN_LARM].name1 == ART_STORMBRINGER) stormbringer = TRUE; + if (p_ptr->inventory_list[INVEN_RARM].name1 == ART_STORMBRINGER) stormbringer = TRUE; + if (p_ptr->inventory_list[INVEN_LARM].name1 == ART_STORMBRINGER) stormbringer = TRUE; if (stormbringer) { msg_format(_("黒い刃は強欲に%sを攻撃した!", "Your black blade greedily attacks %s!"), m_name); - chg_virtue(V_INDIVIDUALISM, 1); - chg_virtue(V_HONOUR, -1); - chg_virtue(V_JUSTICE, -1); - chg_virtue(V_COMPASSION, -1); + chg_virtue(p_ptr, V_INDIVIDUALISM, 1); + chg_virtue(p_ptr, V_HONOUR, -1); + chg_virtue(p_ptr, V_JUSTICE, -1); + chg_virtue(p_ptr, V_COMPASSION, -1); } else if (p_ptr->pclass != CLASS_BERSERKER) { if (get_check(_("本当に攻撃しますか?", "Really hit it? "))) { - chg_virtue(V_INDIVIDUALISM, 1); - chg_virtue(V_HONOUR, -1); - chg_virtue(V_JUSTICE, -1); - chg_virtue(V_COMPASSION, -1); + chg_virtue(p_ptr, V_INDIVIDUALISM, 1); + chg_virtue(p_ptr, V_HONOUR, -1); + chg_virtue(p_ptr, V_JUSTICE, -1); + chg_virtue(p_ptr, V_COMPASSION, -1); } else { @@ -1420,8 +2265,8 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) if (MON_CSLEEP(m_ptr)) /* It is not honorable etc to attack helpless victims */ { - if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5)) chg_virtue(V_COMPASSION, -1); - if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5)) chg_virtue(V_HONOUR, -1); + if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5)) chg_virtue(p_ptr, V_COMPASSION, -1); + if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5)) chg_virtue(p_ptr, V_HONOUR, -1); } if (p_ptr->migite && p_ptr->hidarite) @@ -1448,7 +2293,7 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) if (cur < max) { - DEPTH ridinglevel = r_info[m_list[p_ptr->riding].r_idx].level; + DEPTH ridinglevel = r_info[current_floor_ptr->m_list[p_ptr->riding].r_idx].level; DEPTH targetlevel = r_ptr->level; int inc = 0; @@ -1469,7 +2314,7 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) } } - riding_t_m_idx = g_ptr->m_idx; + p_ptr->riding_t_m_idx = g_ptr->m_idx; if (p_ptr->migite) py_attack_aux(y, x, &fear, &mdeath, 0, mode); if (p_ptr->hidarite && !mdeath) py_attack_aux(y, x, &fear, &mdeath, 1, mode); @@ -1498,7 +2343,7 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) if ((p_ptr->special_defense & KATA_IAI) && ((mode != HISSATSU_IAI) || mdeath)) { - set_action(ACTION_NONE); + set_action(p_ptr, ACTION_NONE); } return mdeath; @@ -1511,7 +2356,7 @@ bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode) */ bool make_attack_normal(MONSTER_IDX m_idx) { - monster_type *m_ptr = &m_list[m_idx]; + monster_type *m_ptr = ¤t_floor_ptr->m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int ap_cnt; @@ -1546,12 +2391,10 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Extract the effective monster level */ rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); - /* Get the monster name (or "it") */ monster_desc(m_name, m_ptr, 0); - /* Get the "died from" information (i.e. "a kobold") */ - monster_desc(ddesc, m_ptr, MD_IGNORE_HALLU | MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE); + monster_desc(ddesc, m_ptr, MD_WRONGDOER_NAME); if (p_ptr->special_defense & KATA_IAI) { @@ -1583,8 +2426,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) int d_dice = r_ptr->blow[ap_cnt].d_dice; int d_side = r_ptr->blow[ap_cnt].d_side; - - if (!m_ptr->r_idx) break; + if (!monster_is_valid(m_ptr)) break; /* Hack -- no more attacks */ if (!method) break; @@ -1975,7 +2817,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Take "poison" effect */ if (!(p_ptr->resist_pois || IS_OPPOSE_POIS()) && !CHECK_MULTISHADOW()) { - if (set_poisoned(p_ptr->poisoned + randint1(rlev) + 5)) + if (set_poisoned(p_ptr, p_ptr->poisoned + randint1(rlev) + 5)) { obvious = TRUE; } @@ -2026,9 +2868,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) i = (INVENTORY_IDX)randint0(INVEN_PACK); /* Obtain the item */ - o_ptr = &inventory[i]; - - /* Skip non-objects */ + o_ptr = &p_ptr->inventory_list[i]; if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs */ @@ -2108,13 +2948,13 @@ bool make_attack_normal(MONSTER_IDX m_idx) { msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter.")); msg_format(_("$%ld のお金が盗まれた!", "%ld coins were stolen!"), (long)gold); - chg_virtue(V_SACRIFICE, 1); + chg_virtue(p_ptr, V_SACRIFICE, 1); } else { msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter.")); msg_print(_("お金が全部盗まれた!", "All of your coins were stolen!")); - chg_virtue(V_SACRIFICE, 2); + chg_virtue(p_ptr, V_SACRIFICE, 2); } /* Redraw gold */ @@ -2161,9 +3001,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) i = (INVENTORY_IDX)randint0(INVEN_PACK); /* Obtain the item */ - o_ptr = &inventory[i]; - - /* Skip non-objects */ + o_ptr = &p_ptr->inventory_list[i]; if (!o_ptr->k_idx) continue; /* Skip artifacts */ @@ -2176,18 +3014,14 @@ bool make_attack_normal(MONSTER_IDX m_idx) #else msg_format("%sour %s (%c) was stolen!", ((o_ptr->number > 1) ? "One of y" : "Y"), o_name, index_to_label(i)); #endif - - chg_virtue(V_SACRIFICE, 1); - - - /* Make an object */ + chg_virtue(p_ptr, V_SACRIFICE, 1); o_idx = o_pop(); /* Success */ if (o_idx) { object_type *j_ptr; - j_ptr = &o_list[o_idx]; + j_ptr = ¤t_floor_ptr->o_list[o_idx]; object_copy(j_ptr, o_ptr); /* Modify number */ @@ -2243,9 +3077,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Pick an item from the pack */ i = (INVENTORY_IDX)randint0(INVEN_PACK); - o_ptr = &inventory[i]; - - /* Skip non-objects */ + o_ptr = &p_ptr->inventory_list[i]; if (!o_ptr->k_idx) continue; /* Skip non-food objects */ @@ -2274,7 +3106,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) case RBE_EAT_LITE: { /* Access the lite */ - o_ptr = &inventory[INVEN_LITE]; + o_ptr = &p_ptr->inventory_list[INVEN_LITE]; get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; @@ -2347,7 +3179,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Increase "blind" */ if (!p_ptr->resist_blind && !CHECK_MULTISHADOW()) { - if (set_blind(p_ptr->blind + 10 + randint1(rlev))) + if (set_blind(p_ptr, p_ptr->blind + 10 + randint1(rlev))) { #ifdef JP if (m_ptr->r_idx == MON_DIO) msg_print("どうだッ!この血の目潰しはッ!"); @@ -2374,7 +3206,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Increase "confused" */ if (!p_ptr->resist_conf && !CHECK_MULTISHADOW()) { - if (set_confused(p_ptr->confused + 3 + randint1(rlev))) + if (set_confused(p_ptr, p_ptr->confused + 3 + randint1(rlev))) { obvious = TRUE; } @@ -2409,7 +3241,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } else { - if (set_afraid(p_ptr->afraid + 3 + randint1(rlev))) + if (set_afraid(p_ptr, p_ptr->afraid + 3 + randint1(rlev))) { obvious = TRUE; } @@ -2446,7 +3278,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) { if (!p_ptr->paralyzed) { - if (set_paralyzed(3 + randint1(rlev))) + if (set_paralyzed(p_ptr, 3 + randint1(rlev))) { obvious = TRUE; } @@ -2464,7 +3296,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_STR)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_STR)) obvious = TRUE; break; } @@ -2474,7 +3306,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_INT)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_INT)) obvious = TRUE; break; } @@ -2484,7 +3316,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_WIS)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_WIS)) obvious = TRUE; break; } @@ -2494,7 +3326,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_DEX)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_DEX)) obvious = TRUE; break; } @@ -2504,7 +3336,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_CON)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_CON)) obvious = TRUE; break; } @@ -2514,7 +3346,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) get_damage += take_hit(DAMAGE_ATTACK, damage, ddesc, -1); if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - if (do_dec_stat(A_CHR)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_CHR)) obvious = TRUE; break; } @@ -2526,12 +3358,12 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; /* Damage (stats) */ - if (do_dec_stat(A_STR)) obvious = TRUE; - if (do_dec_stat(A_DEX)) obvious = TRUE; - if (do_dec_stat(A_CON)) obvious = TRUE; - if (do_dec_stat(A_INT)) obvious = TRUE; - if (do_dec_stat(A_WIS)) obvious = TRUE; - if (do_dec_stat(A_CHR)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_STR)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_DEX)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_CON)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_INT)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_WIS)) obvious = TRUE; + if (do_dec_stat(p_ptr, A_CHR)) obvious = TRUE; break; } @@ -2548,7 +3380,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Radius 8 earthquake centered at the monster */ if (damage > 23 || explode) { - earthquake_aux(m_ptr->fy, m_ptr->fx, 8, m_idx); + earthquake(m_ptr->fy, m_ptr->fx, 8, m_idx); } break; @@ -2564,7 +3396,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - (void)drain_exp(d, d / 10, 95); + (void)drain_exp(p_ptr, d, d / 10, 95); break; } @@ -2578,7 +3410,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - (void)drain_exp(d, d / 10, 90); + (void)drain_exp(p_ptr, d, d / 10, 90); break; } @@ -2592,7 +3424,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - (void)drain_exp(d, d / 10, 75); + (void)drain_exp(p_ptr, d, d / 10, 75); break; } @@ -2606,7 +3438,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - (void)drain_exp(d, d / 10, 50); + (void)drain_exp(p_ptr, d, d / 10, 50); break; } @@ -2619,7 +3451,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Take "poison" effect */ if (!(p_ptr->resist_pois || IS_OPPOSE_POIS())) { - if (set_poisoned(p_ptr->poisoned + randint1(rlev) + 5)) + if (set_poisoned(p_ptr, p_ptr->poisoned + randint1(rlev) + 5)) { obvious = TRUE; } @@ -2630,7 +3462,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) { /* 1% chance for perm. damage */ bool perm = one_in_(10); - if (dec_stat(A_CON, randint1(10), perm)) + if (dec_stat(p_ptr, A_CON, randint1(10), perm)) { msg_print(_("病があなたを蝕んでいる気がする。", "You feel strange sickness.")); obvious = TRUE; @@ -2650,7 +3482,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) { if (p_ptr->prace == RACE_ANDROID) break; msg_print(_("人生が逆戻りした気がする。", "You feel life has clocked back.")); - lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); + lose_exp(p_ptr, 100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE); break; } @@ -2714,7 +3546,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->is_dead || CHECK_MULTISHADOW()) break; - resist_drain = !drain_exp(d, d / 10, 50); + resist_drain = !drain_exp(p_ptr, d, d / 10, 50); /* Heal the attacker? */ if (p_ptr->mimic_form) @@ -2801,7 +3633,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } else { - if (set_slow((p_ptr->slow + 4 + randint0(rlev / 10)), FALSE)) + if (set_slow(p_ptr, (p_ptr->slow + 4 + randint0(rlev / 10)), FALSE)) { obvious = TRUE; } @@ -2822,7 +3654,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } else { - if (set_stun(p_ptr->stun + 10 + randint1(r_ptr->level / 4))) + if (set_stun(p_ptr, p_ptr->stun + 10 + randint1(r_ptr->level / 4))) { obvious = TRUE; } @@ -2870,7 +3702,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } /* Apply the cut */ - if (cut_plus) (void)set_cut(p_ptr->cut + cut_plus); + if (cut_plus) (void)set_cut(p_ptr,p_ptr->cut + cut_plus); } /* Handle stun */ @@ -2895,7 +3727,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } /* Apply the stun */ - if (stun_plus) (void)set_stun(p_ptr->stun + stun_plus); + if (stun_plus) (void)set_stun(p_ptr, p_ptr->stun + stun_plus); } if (explode) @@ -3004,7 +3836,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_RES_SHAR_MASK); } - if (is_mirror_grid(¤t_floor->grid_array[p_ptr->y][p_ptr->x])) + if (is_mirror_grid(¤t_floor_ptr->grid_array[p_ptr->y][p_ptr->x])) { teleport_player(10, 0L); } @@ -3064,7 +3896,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (hex_spelling(HEX_SHADOW_CLOAK) && alive && !p_ptr->is_dead) { HIT_POINT dam = 1; - object_type *o_armed_ptr = &inventory[INVEN_RARM]; + object_type *o_armed_ptr = &p_ptr->inventory_list[INVEN_RARM]; if (!(r_ptr->flagsr & RFR_RES_ALL || r_ptr->flagsr & RFR_RES_DARK)) { @@ -3075,7 +3907,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } /* Cursed armor makes damages doubled */ - o_armed_ptr = &inventory[INVEN_BODY]; + o_armed_ptr = &p_ptr->inventory_list[INVEN_BODY]; if ((o_armed_ptr->k_idx) && object_is_cursed(o_armed_ptr)) dam *= 2; /* Modify the damage */ @@ -3101,7 +3933,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Some cursed armours gives an extra effect */ for (j = 0; j < 4; j++) { - o_armed_ptr = &inventory[typ[j][0]]; + o_armed_ptr = &p_ptr->inventory_list[typ[j][0]]; if ((o_armed_ptr->k_idx) && object_is_cursed(o_armed_ptr) && object_is_armour(o_armed_ptr)) project(0, 0, m_ptr->fy, m_ptr->fx, (p_ptr->lev * 2), typ[j][1], flg, -1); } @@ -3138,7 +3970,6 @@ bool make_attack_normal(MONSTER_IDX m_idx) /* Visible monsters */ if (m_ptr->ml) { - /* Disturbing */ disturb(TRUE, TRUE); #ifdef JP @@ -3154,7 +3985,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) } /* Gain shield experience */ - if (object_is_armour(&inventory[INVEN_RARM]) || object_is_armour(&inventory[INVEN_LARM])) + if (object_is_armour(&p_ptr->inventory_list[INVEN_RARM]) || object_is_armour(&p_ptr->inventory_list[INVEN_LARM])) { int cur = p_ptr->skill_exp[GINOU_SHIELD]; int max = s_info[p_ptr->pclass].s_max[GINOU_SHIELD]; @@ -3203,7 +4034,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->riding && damage) { char m_steed_name[MAX_NLEN]; - monster_desc(m_steed_name, &m_list[p_ptr->riding], 0); + monster_desc(m_steed_name, ¤t_floor_ptr->m_list[p_ptr->riding], 0); if (rakuba((damage > 200) ? 200 : damage, FALSE)) { msg_format(_("%^sから落ちてしまった!", "You have fallen from %s."), m_steed_name); @@ -3233,7 +4064,7 @@ bool make_attack_normal(MONSTER_IDX m_idx) msg_format("The attack of %s has wounded %s!", m_name, m_name_self); #endif project(0, 0, m_ptr->fy, m_ptr->fx, get_damage, GF_MISSILE, PROJECT_KILL, -1); - if (p_ptr->tim_eyeeye) set_tim_eyeeye(p_ptr->tim_eyeeye-5, TRUE); + if (p_ptr->tim_eyeeye) set_tim_eyeeye(p_ptr, p_ptr->tim_eyeeye-5, TRUE); } if ((p_ptr->counter || (p_ptr->special_defense & KATA_MUSOU)) && alive && !p_ptr->is_dead && m_ptr->ml && (p_ptr->csp > 7)) @@ -3277,9 +4108,825 @@ bool make_attack_normal(MONSTER_IDX m_idx) if (p_ptr->special_defense & KATA_IAI) { - set_action(ACTION_NONE); + set_action(p_ptr, ACTION_NONE); } /* Assume we attacked */ return (TRUE); } + + +#define BLOW_EFFECT_TYPE_NONE 0 +#define BLOW_EFFECT_TYPE_FEAR 1 +#define BLOW_EFFECT_TYPE_SLEEP 2 +#define BLOW_EFFECT_TYPE_HEAL 3 + +/*! + * @brief モンスターから敵モンスターへの打撃攻撃処理 + * @param m_idx 攻撃側モンスターの参照ID + * @param t_idx 目標側モンスターの参照ID + * @return 実際に打撃処理が行われた場合TRUEを返す + */ +bool monst_attack_monst(MONSTER_IDX m_idx, MONSTER_IDX t_idx) +{ + monster_type *m_ptr = ¤t_floor_ptr->m_list[m_idx]; + monster_type *t_ptr = ¤t_floor_ptr->m_list[t_idx]; + + monster_race *r_ptr = &r_info[m_ptr->r_idx]; + monster_race *tr_ptr = &r_info[t_ptr->r_idx]; + + ARMOUR_CLASS ap_cnt; + ARMOUR_CLASS ac; + DEPTH rlev; + int pt; + GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN]; + char temp[MAX_NLEN]; + bool blinked; + bool explode = FALSE, touched = FALSE, fear = FALSE, dead = FALSE; + POSITION y_saver = t_ptr->fy; + POSITION x_saver = t_ptr->fx; + int effect_type; + + bool see_m = is_seen(m_ptr); + bool see_t = is_seen(t_ptr); + bool see_either = see_m || see_t; + + /* Can the player be aware of this attack? */ + bool known = (m_ptr->cdis <= MAX_SIGHT) || (t_ptr->cdis <= MAX_SIGHT); + bool do_silly_attack = (one_in_(2) && p_ptr->image); + + /* Cannot attack self */ + if (m_idx == t_idx) return FALSE; + + /* Not allowed to attack */ + if (r_ptr->flags1 & RF1_NEVER_BLOW) return FALSE; + + if (d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_MELEE) return (FALSE); + + /* Total armor */ + ac = tr_ptr->ac; + + /* Extract the effective monster level */ + rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); + + monster_desc(m_name, m_ptr, 0); + monster_desc(t_name, t_ptr, 0); + + /* Assume no blink */ + blinked = FALSE; + + if (!see_either && known) + { + current_floor_ptr->monster_noise = TRUE; + } + + if (p_ptr->riding && (m_idx == p_ptr->riding)) disturb(TRUE, TRUE); + + /* Scan through all four blows */ + for (ap_cnt = 0; ap_cnt < 4; ap_cnt++) + { + bool obvious = FALSE; + + HIT_POINT power = 0; + HIT_POINT damage = 0; + + concptr act = NULL; + + /* Extract the attack infomation */ + int effect = r_ptr->blow[ap_cnt].effect; + int method = r_ptr->blow[ap_cnt].method; + int d_dice = r_ptr->blow[ap_cnt].d_dice; + int d_side = r_ptr->blow[ap_cnt].d_side; + + if (!monster_is_valid(m_ptr)) break; + + /* Stop attacking if the target dies! */ + if (t_ptr->fx != x_saver || t_ptr->fy != y_saver) + break; + + /* Hack -- no more attacks */ + if (!method) break; + + if (method == RBM_SHOOT) continue; + + /* Extract the attack "power" */ + power = mbe_info[effect].power; + + /* Monster hits */ + if (!effect || check_hit2(power, rlev, ac, MON_STUNNED(m_ptr))) + { + (void)set_monster_csleep(t_idx, 0); + + if (t_ptr->ml) + { + /* Redraw the health bar */ + if (p_ptr->health_who == t_idx) p_ptr->redraw |= (PR_HEALTH); + if (p_ptr->riding == t_idx) p_ptr->redraw |= (PR_UHEALTH); + } + + /* Describe the attack method */ + switch (method) + { + case RBM_HIT: + { + act = _("%sを殴った。", "hits %s."); + touched = TRUE; + break; + } + + case RBM_TOUCH: + { + act = _("%sを触った。", "touches %s."); + touched = TRUE; + break; + } + + case RBM_PUNCH: + { + act = _("%sをパンチした。", "punches %s."); + touched = TRUE; + break; + } + + case RBM_KICK: + { + act = _("%sを蹴った。", "kicks %s."); + touched = TRUE; + break; + } + + case RBM_CLAW: + { + act = _("%sをひっかいた。", "claws %s."); + touched = TRUE; + break; + } + + case RBM_BITE: + { + act = _("%sを噛んだ。", "bites %s."); + touched = TRUE; + break; + } + + case RBM_STING: + { + act = _("%sを刺した。", "stings %s."); + touched = TRUE; + break; + } + + case RBM_SLASH: + { + act = _("%sを斬った。", "slashes %s."); + break; + } + + case RBM_BUTT: + { + act = _("%sを角で突いた。", "butts %s."); + touched = TRUE; + break; + } + + case RBM_CRUSH: + { + act = _("%sに体当りした。", "crushes %s."); + touched = TRUE; + break; + } + + case RBM_ENGULF: + { + act = _("%sを飲み込んだ。", "engulfs %s."); + touched = TRUE; + break; + } + + case RBM_CHARGE: + { + act = _("%sに請求書をよこした。", "charges %s."); + touched = TRUE; + break; + } + + case RBM_CRAWL: + { + act = _("%sの体の上を這い回った。", "crawls on %s."); + touched = TRUE; + break; + } + + case RBM_DROOL: + { + act = _("%sによだれをたらした。", "drools on %s."); + touched = FALSE; + break; + } + + case RBM_SPIT: + { + act = _("%sに唾を吐いた。", "spits on %s."); + touched = FALSE; + break; + } + + case RBM_EXPLODE: + { + if (see_either) disturb(TRUE, TRUE); + act = _("爆発した。", "explodes."); + explode = TRUE; + touched = FALSE; + break; + } + + case RBM_GAZE: + { + act = _("%sをにらんだ。", "gazes at %s."); + touched = FALSE; + break; + } + + case RBM_WAIL: + { + act = _("%sに泣きついた。", "wails at %s."); + touched = FALSE; + break; + } + + case RBM_SPORE: + { + act = _("%sに胞子を飛ばした。", "releases spores at %s."); + touched = FALSE; + break; + } + + case RBM_XXX4: + { + act = _("%sにXXX4を飛ばした。", "projects XXX4's at %s."); + touched = FALSE; + break; + } + + case RBM_BEG: + { + act = _("%sに金をせがんだ。", "begs %s for money."); + touched = FALSE; + break; + } + + case RBM_INSULT: + { + act = _("%sを侮辱した。", "insults %s."); + touched = FALSE; + break; + } + + case RBM_MOAN: + { + act = _("%sにむかってうめいた。", "moans at %s."); + touched = FALSE; + break; + } + + case RBM_SHOW: + { + act = _("%sにむかって歌った。", "sings to %s."); + touched = FALSE; + break; + } + } + + if (act && see_either) + { +#ifdef JP + if (do_silly_attack) act = silly_attacks2[randint0(MAX_SILLY_ATTACK)]; + strfmt(temp, act, t_name); + msg_format("%^sは%s", m_name, temp); +#else + if (do_silly_attack) + { + act = silly_attacks[randint0(MAX_SILLY_ATTACK)]; + strfmt(temp, "%s %s.", act, t_name); + } + else strfmt(temp, act, t_name); + msg_format("%^s %s", m_name, temp); +#endif + } + + /* Hack -- assume all attacks are obvious */ + obvious = TRUE; + + /* Roll out the damage */ + damage = damroll(d_dice, d_side); + + /* Assume no effect */ + effect_type = BLOW_EFFECT_TYPE_NONE; + + pt = GF_MISSILE; + + /* Apply appropriate damage */ + switch (effect) + { + case 0: + case RBE_DR_MANA: + damage = pt = 0; + break; + + case RBE_SUPERHURT: + if ((randint1(rlev * 2 + 250) > (ac + 200)) || one_in_(13)) + { + int tmp_damage = damage - (damage * ((ac < 150) ? ac : 150) / 250); + damage = MAX(damage, tmp_damage * 2); + break; + } + + /* Fall through */ + + case RBE_HURT: + damage -= (damage * ((ac < 150) ? ac : 150) / 250); + break; + + case RBE_POISON: + case RBE_DISEASE: + pt = GF_POIS; + break; + + case RBE_UN_BONUS: + case RBE_UN_POWER: + pt = GF_DISENCHANT; + break; + + case RBE_EAT_ITEM: + case RBE_EAT_GOLD: + if ((p_ptr->riding != m_idx) && one_in_(2)) blinked = TRUE; + break; + + case RBE_EAT_FOOD: + case RBE_EAT_LITE: + case RBE_BLIND: + case RBE_LOSE_STR: + case RBE_LOSE_INT: + case RBE_LOSE_WIS: + case RBE_LOSE_DEX: + case RBE_LOSE_CON: + case RBE_LOSE_CHR: + case RBE_LOSE_ALL: + break; + + case RBE_ACID: + pt = GF_ACID; + break; + + case RBE_ELEC: + pt = GF_ELEC; + break; + + case RBE_FIRE: + pt = GF_FIRE; + break; + + case RBE_COLD: + pt = GF_COLD; + break; + + case RBE_CONFUSE: + pt = GF_CONFUSION; + break; + + case RBE_TERRIFY: + effect_type = BLOW_EFFECT_TYPE_FEAR; + break; + + case RBE_PARALYZE: + effect_type = BLOW_EFFECT_TYPE_SLEEP; + break; + + case RBE_SHATTER: + damage -= (damage * ((ac < 150) ? ac : 150) / 250); + if (damage > 23) earthquake(m_ptr->fy, m_ptr->fx, 8, m_idx); + break; + + case RBE_EXP_10: + case RBE_EXP_20: + case RBE_EXP_40: + case RBE_EXP_80: + pt = GF_NETHER; + break; + + case RBE_TIME: + pt = GF_TIME; + break; + + case RBE_DR_LIFE: + pt = GF_HYPODYNAMIA; + effect_type = BLOW_EFFECT_TYPE_HEAL; + break; + + case RBE_INERTIA: + pt = GF_INERTIAL; + break; + + case RBE_STUN: + pt = GF_SOUND; + break; + + default: + pt = 0; + break; + } + + if (pt) + { + /* Do damage if not exploding */ + if (!explode) + { + project(m_idx, 0, t_ptr->fy, t_ptr->fx, + damage, pt, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + } + + switch (effect_type) + { + case BLOW_EFFECT_TYPE_FEAR: + project(m_idx, 0, t_ptr->fy, t_ptr->fx, + damage, GF_TURN_ALL, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + break; + + case BLOW_EFFECT_TYPE_SLEEP: + project(m_idx, 0, t_ptr->fy, t_ptr->fx, + r_ptr->level, GF_OLD_SLEEP, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + break; + + case BLOW_EFFECT_TYPE_HEAL: + if ((monster_living(m_idx)) && (damage > 2)) + { + bool did_heal = FALSE; + + if (m_ptr->hp < m_ptr->maxhp) did_heal = TRUE; + + /* Heal */ + m_ptr->hp += damroll(4, damage / 6); + if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp; + + /* Redraw (later) if needed */ + if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); + if (p_ptr->riding == m_idx) p_ptr->redraw |= (PR_UHEALTH); + + /* Special message */ + if (see_m && did_heal) + { + msg_format(_("%sは体力を回復したようだ。", "%^s appears healthier."), m_name); + } + } + break; + } + + if (touched) + { + /* Aura fire */ + if ((tr_ptr->flags2 & RF2_AURA_FIRE) && m_ptr->r_idx) + { + if (!(r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK)) + { + if (see_either) + { + msg_format(_("%^sは突然熱くなった!", "%^s is suddenly very hot!"), m_name); + } + if (m_ptr->ml && is_original_ap_and_seen(t_ptr)) tr_ptr->r_flags2 |= RF2_AURA_FIRE; + project(t_idx, 0, m_ptr->fy, m_ptr->fx, + damroll(1 + ((tr_ptr->level) / 26), + 1 + ((tr_ptr->level) / 17)), + GF_FIRE, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + } + else + { + if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK); + } + } + + /* Aura cold */ + if ((tr_ptr->flags3 & RF3_AURA_COLD) && m_ptr->r_idx) + { + if (!(r_ptr->flagsr & RFR_EFF_IM_COLD_MASK)) + { + if (see_either) + { + msg_format(_("%^sは突然寒くなった!", "%^s is suddenly very cold!"), m_name); + } + if (m_ptr->ml && is_original_ap_and_seen(t_ptr)) tr_ptr->r_flags3 |= RF3_AURA_COLD; + project(t_idx, 0, m_ptr->fy, m_ptr->fx, + damroll(1 + ((tr_ptr->level) / 26), + 1 + ((tr_ptr->level) / 17)), + GF_COLD, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + } + else + { + if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_COLD_MASK); + } + } + + /* Aura elec */ + if ((tr_ptr->flags2 & RF2_AURA_ELEC) && m_ptr->r_idx) + { + if (!(r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK)) + { + if (see_either) + { + msg_format(_("%^sは電撃を食らった!", "%^s gets zapped!"), m_name); + } + if (m_ptr->ml && is_original_ap_and_seen(t_ptr)) tr_ptr->r_flags2 |= RF2_AURA_ELEC; + project(t_idx, 0, m_ptr->fy, m_ptr->fx, + damroll(1 + ((tr_ptr->level) / 26), + 1 + ((tr_ptr->level) / 17)), + GF_ELEC, PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED, -1); + } + else + { + if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= (r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK); + } + } + } + } + } + + /* Monster missed player */ + else + { + /* Analyze failed attacks */ + switch (method) + { + case RBM_HIT: + case RBM_TOUCH: + case RBM_PUNCH: + case RBM_KICK: + case RBM_CLAW: + case RBM_BITE: + case RBM_STING: + case RBM_SLASH: + case RBM_BUTT: + case RBM_CRUSH: + case RBM_ENGULF: + case RBM_CHARGE: + { + (void)set_monster_csleep(t_idx, 0); + + /* Visible monsters */ + if (see_m) + { +#ifdef JP + msg_format("%sは%^sの攻撃をかわした。", t_name, m_name); +#else + msg_format("%^s misses %s.", m_name, t_name); +#endif + } + + break; + } + } + } + + + /* Analyze "visible" monsters only */ + if (is_original_ap_and_seen(m_ptr) && !do_silly_attack) + { + /* Count "obvious" attacks (and ones that cause damage) */ + if (obvious || damage || (r_ptr->r_blows[ap_cnt] > 10)) + { + /* Count attacks of this type */ + if (r_ptr->r_blows[ap_cnt] < MAX_UCHAR) + { + r_ptr->r_blows[ap_cnt]++; + } + } + } + } + + if (explode) + { + sound(SOUND_EXPLODE); + + /* Cancel Invulnerability */ + (void)set_monster_invulner(m_idx, 0, FALSE); + mon_take_hit_mon(m_idx, m_ptr->hp + 1, &dead, &fear, _("は爆発して粉々になった。", " explodes into tiny shreds."), m_idx); + blinked = FALSE; + } + + /* Blink away */ + if (blinked && m_ptr->r_idx) + { + if (teleport_barrier(m_idx)) + { + if (see_m) + { + msg_print(_("泥棒は笑って逃げ...ようとしたがバリアに防がれた。", "The thief flees laughing...? But magic barrier obstructs it.")); + } + else if (known) + { + current_floor_ptr->monster_noise = TRUE; + } + } + else + { + if (see_m) + { + msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!")); + } + else if (known) + { + current_floor_ptr->monster_noise = TRUE; + } + + teleport_away(m_idx, MAX_SIGHT * 2 + 5, 0L); + } + } + + return TRUE; +} + + + +/*! + * @brief モンスターが敵モンスターに行う打撃処理 / + * Hack, based on mon_take_hit... perhaps all monster attacks on other monsters should use this? + * @param m_idx 目標となるモンスターの参照ID + * @param dam ダメージ量 + * @param dead 目標となったモンスターの死亡状態を返す参照ポインタ + * @param fear 目標となったモンスターの恐慌状態を返す参照ポインタ + * @param note 目標モンスターが死亡した場合の特別メッセージ(NULLならば標準表示を行う) + * @param who 打撃を行ったモンスターの参照ID + * @return なし + */ +void mon_take_hit_mon(MONSTER_IDX m_idx, HIT_POINT dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who) +{ + monster_type *m_ptr = ¤t_floor_ptr->m_list[m_idx]; + monster_race *r_ptr = &r_info[m_ptr->r_idx]; + GAME_TEXT m_name[160]; + bool seen = is_seen(m_ptr); + + /* Can the player be aware of this attack? */ + bool known = (m_ptr->cdis <= MAX_SIGHT); + + monster_desc(m_name, m_ptr, 0); + + /* Redraw (later) if needed */ + if (m_ptr->ml) + { + if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); + if (p_ptr->riding == m_idx) p_ptr->redraw |= (PR_UHEALTH); + } + + (void)set_monster_csleep(m_idx, 0); + + if (p_ptr->riding && (m_idx == p_ptr->riding)) disturb(TRUE, TRUE); + + if (MON_INVULNER(m_ptr) && randint0(PENETRATE_INVULNERABILITY)) + { + if (seen) + { + msg_format(_("%^sはダメージを受けない。", "%^s is unharmed."), m_name); + } + return; + } + + if (r_ptr->flagsr & RFR_RES_ALL) + { + if (dam > 0) + { + dam /= 100; + if ((dam == 0) && one_in_(3)) dam = 1; + } + if (dam == 0) + { + if (seen) + { + msg_format(_("%^sはダメージを受けない。", "%^s is unharmed."), m_name); + } + return; + } + } + + /* Hurt it */ + m_ptr->hp -= dam; + + /* It is dead now... or is it? */ + if (m_ptr->hp < 0) + { + if (((r_ptr->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) || + (r_ptr->flags7 & RF7_NAZGUL)) && + !p_ptr->phase_out) + { + m_ptr->hp = 1; + } + else + { + /* Make a sound */ + if (!monster_living(m_ptr->r_idx)) + { + sound(SOUND_N_KILL); + } + else + { + sound(SOUND_KILL); + } + + *dead = TRUE; + + if (known) + { + monster_desc(m_name, m_ptr, MD_TRUE_NAME); + /* Unseen death by normal attack */ + if (!seen) + { + current_floor_ptr->monster_noise = TRUE; + } + /* Death by special attack */ + else if (note) + { + msg_format(_("%^s%s", "%^s%s"), m_name, note); + } + /* Death by normal attack -- nonliving monster */ + else if (!monster_living(m_ptr->r_idx)) + { + msg_format(_("%^sは破壊された。", "%^s is destroyed."), m_name); + } + /* Death by normal attack -- living monster */ + else + { + msg_format(_("%^sは殺された。", "%^s is killed."), m_name); + } + } + + monster_gain_exp(who, m_ptr->r_idx); + monster_death(m_idx, FALSE); + delete_monster_idx(m_idx); + + /* Not afraid */ + (*fear) = FALSE; + + /* Monster is dead */ + return; + } + } + + *dead = FALSE; + +#ifdef ALLOW_FEAR + + /* Mega-Hack -- Pain cancels fear */ + if (MON_MONFEAR(m_ptr) && (dam > 0)) + { + /* Cure fear */ + if (set_monster_monfear(m_idx, MON_MONFEAR(m_ptr) - randint1(dam / 4))) + { + /* No more fear */ + (*fear) = FALSE; + } + } + + /* Sometimes a monster gets scared by damage */ + if (!MON_MONFEAR(m_ptr) && !(r_ptr->flags3 & RF3_NO_FEAR)) + { + /* Percentage of fully healthy */ + int percentage = (100L * m_ptr->hp) / m_ptr->maxhp; + + /* + * Run (sometimes) if at 10% or less of max hit points, + * or (usually) when hit for half its current hit points + */ + if (((percentage <= 10) && (randint0(10) < percentage)) || + ((dam >= m_ptr->hp) && (randint0(100) < 80))) + { + /* Hack -- note fear */ + (*fear) = TRUE; + + /* Hack -- Add some timed fear */ + (void)set_monster_monfear(m_idx, (randint1(10) + + (((dam >= m_ptr->hp) && (percentage > 7)) ? + 20 : ((11 - percentage) * 5)))); + } + } + +#endif /* ALLOW_FEAR */ + + if ((dam > 0) && !is_pet(m_ptr) && !is_friendly(m_ptr) && (who != m_idx)) + { + if (is_pet(¤t_floor_ptr->m_list[who]) && !player_bold(m_ptr->target_y, m_ptr->target_x)) + { + set_target(m_ptr, current_floor_ptr->m_list[who].fy, current_floor_ptr->m_list[who].fx); + } + } + + if (p_ptr->riding && (p_ptr->riding == m_idx) && (dam > 0)) + { + monster_desc(m_name, m_ptr, 0); + + if (m_ptr->hp > m_ptr->maxhp / 3) dam = (dam + 1) / 2; + if (rakuba((dam > 200) ? 200 : dam, FALSE)) + { + msg_format(_("%^sに振り落とされた!", "You have thrown off from %s!"), m_name); + } + } + + /* Not dead yet */ + return; +}