From 4ab537b0157f4328c102f328f297b78be0689975 Mon Sep 17 00:00:00 2001 From: Deskull Date: Mon, 11 Feb 2019 22:08:58 +0900 Subject: [PATCH] =?utf8?q?[Refactor]=20#38932=20=E6=96=87=E5=AD=97?= =?utf8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=20UTF-8(BOM)=20/=20LF=20?= =?utf8?q?=E3=81=AB=E7=B5=B1=E4=B8=80=E3=80=82=20/=20Unify=20UTF-8(BOM)=20?= =?utf8?q?+=20LF.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/chest.h | 8 +- src/cmd-eat.c | 1038 ++--- src/cmd-eat.h | 6 +- src/cmd-item.h | 32 +- src/cmd-pet.h | 18 +- src/cmd-quaff.c | 1222 ++--- src/cmd-quaff.h | 8 +- src/cmd-read.c | 1278 +++--- src/cmd-read.h | 8 +- src/cmd-spell.c | 2790 ++++++------ src/cmd-spell.h | 48 +- src/cmd-usestaff.c | 894 ++-- src/cmd-usestaff.h | 6 +- src/floor-events.c | 230 +- src/floor-events.h | 6 +- src/gameoption.h | 340 +- src/gamevalue.h | 266 +- src/history.h | 42 +- src/main-win.c | 11598 +++++++++++++++++++++++------------------------ src/melee.h | 12 +- src/monster-status.h | 10 +- src/monsterrace-hook.h | 138 +- src/object-curse.c | 206 +- src/object-curse.h | 4 +- src/object-hook.h | 56 +- src/objectkind-hook.h | 24 +- src/player-damage.h | 28 +- src/realm-arcane.h | 2 +- src/realm-chaos.h | 2 +- src/realm-craft.h | 2 +- src/realm-crusade.h | 2 +- src/realm-daemon.h | 4 +- src/realm-death.h | 2 +- src/realm-hex.h | 28 +- src/realm-hissatsu.h | 2 +- src/realm-life.h | 2 +- src/realm-nature.c | 1134 ++--- src/realm-nature.h | 2 +- src/realm-song.h | 2 +- src/realm-sorcery.h | 2 +- src/realm-trump.h | 2 +- src/rooms-city.c | 518 +-- src/rooms-city.h | 34 +- src/rooms-fractal.c | 136 +- src/rooms-fractal.h | 4 +- src/rooms-normal.c | 2094 ++++----- src/rooms-normal.h | 12 +- src/rooms-pitnest.c | 2002 ++++---- src/rooms-pitnest.h | 24 +- src/rooms-special.c | 484 +- src/rooms-special.h | 4 +- src/rooms-trap.c | 176 +- src/rooms-trap.h | 2 +- src/rooms-vault.c | 2602 +++++------ src/rooms-vault.h | 10 +- src/selfinfo.c | 3616 +++++++-------- src/selfinfo.h | 16 +- src/spells-status.c | 112 +- src/spells-status.h | 2 +- src/spells-summon.c | 606 +-- src/spells-summon.h | 26 +- src/store.h | 88 +- src/trap.c | 1146 ++--- src/trap.h | 80 +- src/world.c | 86 +- src/world.h | 4 +- 66 files changed, 17694 insertions(+), 17694 deletions(-) diff --git a/src/chest.h b/src/chest.h index 41cf6a353..99b171f56 100644 --- a/src/chest.h +++ b/src/chest.h @@ -1,4 +1,4 @@ - -extern void chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx); -extern void chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx); - + +extern void chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx); +extern void chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx); + diff --git a/src/cmd-eat.c b/src/cmd-eat.c index ff13dc283..0b2c6ea3a 100644 --- a/src/cmd-eat.c +++ b/src/cmd-eat.c @@ -1,519 +1,519 @@ -/*! - * @file cmd-eat.c - * @brief プレイヤーの食べるコマンド実装 - * @date 2018/09/07 - * @details - * cmd6.cより分離。 - */ - - -#include "angband.h" -#include "object-hook.h" -#include "avatar.h" -#include "spells-status.h" -#include "realm-hex.h" -#include "player-status.h" - -/*! - * @brief 食料を食べるコマンドのサブルーチン - * @param item 食べるオブジェクトの所持品ID - * @return なし - */ -void do_cmd_eat_food_aux(INVENTORY_IDX item) -{ - int ident, lev; - object_type *o_ptr; - - if (music_singing_any()) stop_singing(); - if (hex_spelling_any()) stop_hex_spell_all(); - - /* Get the item (in the pack) */ - if (item >= 0) - { - o_ptr = &inventory[item]; - } - - /* Get the item (on the floor) */ - else - { - o_ptr = &o_list[0 - item]; - } - - sound(SOUND_EAT); - - take_turn(p_ptr, 100);; - - /* Identity not known yet */ - ident = FALSE; - - /* Object level */ - lev = k_info[o_ptr->k_idx].level; - - if (o_ptr->tval == TV_FOOD) - { - /* Analyze the food */ - switch (o_ptr->sval) - { - case SV_FOOD_POISON: - { - if (!(p_ptr->resist_pois || IS_OPPOSE_POIS())) - { - if (set_poisoned(p_ptr->poisoned + randint0(10) + 10)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_BLINDNESS: - { - if (!p_ptr->resist_blind) - { - if (set_blind(p_ptr->blind + randint0(200) + 200)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_PARANOIA: - { - if (!p_ptr->resist_fear) - { - if (set_afraid(p_ptr->afraid + randint0(10) + 10)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_CONFUSION: - { - if (!p_ptr->resist_conf) - { - if (set_confused(p_ptr->confused + randint0(10) + 10)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_HALLUCINATION: - { - if (!p_ptr->resist_chaos) - { - if (set_image(p_ptr->image + randint0(250) + 250)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_PARALYSIS: - { - if (!p_ptr->free_act) - { - if (set_paralyzed(p_ptr->paralyzed + randint0(10) + 10)) - { - ident = TRUE; - } - } - break; - } - - case SV_FOOD_WEAKNESS: - { - take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_STR); - ident = TRUE; - break; - } - - case SV_FOOD_SICKNESS: - { - take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_CON); - ident = TRUE; - break; - } - - case SV_FOOD_STUPIDITY: - { - take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_INT); - ident = TRUE; - break; - } - - case SV_FOOD_NAIVETY: - { - take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_WIS); - ident = TRUE; - break; - } - - case SV_FOOD_UNHEALTH: - { - take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_CON); - ident = TRUE; - break; - } - - case SV_FOOD_DISEASE: - { - take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1); - (void)do_dec_stat(A_STR); - ident = TRUE; - break; - } - - case SV_FOOD_CURE_POISON: - { - if (set_poisoned(0)) ident = TRUE; - break; - } - - case SV_FOOD_CURE_BLINDNESS: - { - if (set_blind(0)) ident = TRUE; - break; - } - - case SV_FOOD_CURE_PARANOIA: - { - if (set_afraid(0)) ident = TRUE; - break; - } - - case SV_FOOD_CURE_CONFUSION: - { - if (set_confused(0)) ident = TRUE; - break; - } - - case SV_FOOD_CURE_SERIOUS: - { - ident = cure_serious_wounds(4, 8); - break; - } - - case SV_FOOD_RESTORE_STR: - { - if (do_res_stat(A_STR)) ident = TRUE; - break; - } - - case SV_FOOD_RESTORE_CON: - { - if (do_res_stat(A_CON)) ident = TRUE; - break; - } - - case SV_FOOD_RESTORING: - { - ident = restore_all_status(); - break; - } - - -#ifdef JP - /* それぞれの食べ物の感想をオリジナルより細かく表現 */ - case SV_FOOD_BISCUIT: - { - msg_print("甘くてサクサクしてとてもおいしい。"); - ident = TRUE; - break; - } - - case SV_FOOD_JERKY: - { - msg_print("歯ごたえがあっておいしい。"); - ident = TRUE; - break; - } - - case SV_FOOD_SLIME_MOLD: - { - msg_print("これはなんとも形容しがたい味だ。"); - ident = TRUE; - break; - } - - case SV_FOOD_RATION: - { - msg_print("これはおいしい。"); - ident = TRUE; - break; - } -#else - case SV_FOOD_RATION: - case SV_FOOD_BISCUIT: - case SV_FOOD_JERKY: - case SV_FOOD_SLIME_MOLD: - { - msg_print("That tastes good."); - ident = TRUE; - break; - } -#endif - - - case SV_FOOD_WAYBREAD: - { - msg_print(_("これはひじょうに美味だ。", "That tastes good.")); - (void)set_poisoned(0); - (void)hp_player(damroll(4, 8)); - ident = TRUE; - break; - } - -#ifdef JP - case SV_FOOD_PINT_OF_ALE: - { - msg_print("のどごし爽やかだ。"); - ident = TRUE; - break; - } - - case SV_FOOD_PINT_OF_WINE: - { - msg_print("That tastes good."); - ident = TRUE; - break; - } -#else - case SV_FOOD_PINT_OF_ALE: - case SV_FOOD_PINT_OF_WINE: - { - msg_print("That tastes good."); - ident = TRUE; - break; - } -#endif - - } - } - p_ptr->update |= (PU_COMBINE | PU_REORDER); - - if (!(object_is_aware(o_ptr))) - { - chg_virtue(V_KNOWLEDGE, -1); - chg_virtue(V_PATIENCE, -1); - chg_virtue(V_CHANCE, 1); - } - - /* We have tried it */ - if (o_ptr->tval == TV_FOOD) object_tried(o_ptr); - - /* The player is now aware of the object */ - if (ident && !object_is_aware(o_ptr)) - { - object_aware(o_ptr); - gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); - } - - p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); - - - /* Food can feed the player */ - if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) - { - /* Reduced nutritional benefit */ - (void)set_food(p_ptr->food + (o_ptr->pval / 10)); - msg_print(_("あなたのような者にとって食糧など僅かな栄養にしかならない。", - "Mere victuals hold scant sustenance for a being such as yourself.")); - - if (p_ptr->food < PY_FOOD_ALERT) /* Hungry */ - msg_print(_("あなたの飢えは新鮮な血によってのみ満たされる!", - "Your hunger can only be satisfied with fresh blood!")); - } - else if ((prace_is_(RACE_SKELETON) || - prace_is_(RACE_GOLEM) || - prace_is_(RACE_ZOMBIE) || - prace_is_(RACE_SPECTRE)) && - (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) - { - concptr staff; - - if (o_ptr->tval == TV_STAFF && - (item < 0) && (o_ptr->number > 1)) - { - msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs.")); - return; - } - staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand"); - - /* "Eat" charges */ - if (o_ptr->pval == 0) - { - msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff); - o_ptr->ident |= (IDENT_EMPTY); - p_ptr->update |= (PU_COMBINE | PU_REORDER); - p_ptr->window |= (PW_INVEN); - - return; - } - msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff); - - /* Use a single charge */ - o_ptr->pval--; - - /* Eat a charge */ - set_food(p_ptr->food + 5000); - - /* XXX Hack -- unstack if necessary */ - if (o_ptr->tval == TV_STAFF && - (item >= 0) && (o_ptr->number > 1)) - { - object_type forge; - object_type *q_ptr; - q_ptr = &forge; - - /* Obtain a local object */ - object_copy(q_ptr, o_ptr); - - /* Modify quantity */ - q_ptr->number = 1; - - /* Restore the charges */ - o_ptr->pval++; - - /* Unstack the used item */ - o_ptr->number--; - p_ptr->total_weight -= q_ptr->weight; - item = inven_carry(q_ptr); - - msg_format(_("杖をまとめなおした。", "You unstack your staff.")); - } - - /* Describe charges in the pack */ - if (item >= 0) - { - inven_item_charges(item); - } - - /* Describe charges on the floor */ - else - { - floor_item_charges(0 - item); - } - - p_ptr->window |= (PW_INVEN | PW_EQUIP); - - /* Don't eat a staff/wand itself */ - return; - } - else if ((prace_is_(RACE_DEMON) || - (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON)) && - (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE && - my_strchr("pht", r_info[o_ptr->pval].d_char))) - { - /* Drain vitality of humanoids */ - GAME_TEXT o_name[MAX_NLEN]; - object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); - msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%^s is burnt to ashes. You absorb its vitality!"), o_name); - (void)set_food(PY_FOOD_MAX - 1); - } - else if (prace_is_(RACE_SKELETON)) - { -#if 0 - if (o_ptr->tval == TV_SKELETON || - (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON)) - { - msg_print(_("あなたは骨で自分の体を補った。", "Your body absorbs the bone.")); - set_food(p_ptr->food + 5000); - } - else -#endif - - if (!((o_ptr->sval == SV_FOOD_WAYBREAD) || - (o_ptr->sval < SV_FOOD_BISCUIT))) - { - object_type forge; - object_type *q_ptr = &forge; - - msg_print(_("食べ物がアゴを素通りして落ちた!", "The food falls through your jaws!")); - object_prep(q_ptr, lookup_kind(o_ptr->tval, o_ptr->sval)); - - /* Drop the object from heaven */ - (void)drop_near(q_ptr, -1, p_ptr->y, p_ptr->x); - } - else - { - msg_print(_("食べ物がアゴを素通りして落ち、消えた!", "The food falls through your jaws and vanishes!")); - } - } - else if (prace_is_(RACE_GOLEM) || - prace_is_(RACE_ZOMBIE) || - prace_is_(RACE_ENT) || - prace_is_(RACE_DEMON) || - prace_is_(RACE_ANDROID) || - prace_is_(RACE_SPECTRE) || - (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING)) - { - msg_print(_("生者の食物はあなたにとってほとんど栄養にならない。", "The food of mortals is poor sustenance for you.")); - set_food(p_ptr->food + ((o_ptr->pval) / 20)); - } - else if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD) - { - /* Waybread is always fully satisfying. */ - set_food(MAX(p_ptr->food, PY_FOOD_MAX - 1)); - } - else - { - /* Food can feed the player */ - (void)set_food(p_ptr->food + o_ptr->pval); - } - - /* Destroy a food in the pack */ - if (item >= 0) - { - inven_item_increase(item, -1); - inven_item_describe(item); - inven_item_optimize(item); - } - - /* Destroy a food on the floor */ - else - { - floor_item_increase(0 - item, -1); - floor_item_describe(0 - item); - floor_item_optimize(0 - item); - } -} - - -/*! - * @brief 食料を食べるコマンドのメインルーチン / - * Eat some food (from the pack or floor) - * @return なし - */ -void do_cmd_eat_food(void) -{ - OBJECT_IDX item; - concptr q, s; - - if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) - { - set_action(ACTION_NONE); - } - - /* Restrict choices to food */ - item_tester_hook = item_tester_hook_eatable; - - q = _("どれを食べますか? ", "Eat which item? "); - s = _("食べ物がない。", "You have nothing to eat."); - - if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; - - /* Eat the object */ - do_cmd_eat_food_aux(item); -} - +/*! + * @file cmd-eat.c + * @brief プレイヤーの食べるコマンド実装 + * @date 2018/09/07 + * @details + * cmd6.cより分離。 + */ + + +#include "angband.h" +#include "object-hook.h" +#include "avatar.h" +#include "spells-status.h" +#include "realm-hex.h" +#include "player-status.h" + +/*! + * @brief 食料を食べるコマンドのサブルーチン + * @param item 食べるオブジェクトの所持品ID + * @return なし + */ +void do_cmd_eat_food_aux(INVENTORY_IDX item) +{ + int ident, lev; + object_type *o_ptr; + + if (music_singing_any()) stop_singing(); + if (hex_spelling_any()) stop_hex_spell_all(); + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + sound(SOUND_EAT); + + take_turn(p_ptr, 100);; + + /* Identity not known yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[o_ptr->k_idx].level; + + if (o_ptr->tval == TV_FOOD) + { + /* Analyze the food */ + switch (o_ptr->sval) + { + case SV_FOOD_POISON: + { + if (!(p_ptr->resist_pois || IS_OPPOSE_POIS())) + { + if (set_poisoned(p_ptr->poisoned + randint0(10) + 10)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_BLINDNESS: + { + if (!p_ptr->resist_blind) + { + if (set_blind(p_ptr->blind + randint0(200) + 200)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_PARANOIA: + { + if (!p_ptr->resist_fear) + { + if (set_afraid(p_ptr->afraid + randint0(10) + 10)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_CONFUSION: + { + if (!p_ptr->resist_conf) + { + if (set_confused(p_ptr->confused + randint0(10) + 10)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_HALLUCINATION: + { + if (!p_ptr->resist_chaos) + { + if (set_image(p_ptr->image + randint0(250) + 250)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_PARALYSIS: + { + if (!p_ptr->free_act) + { + if (set_paralyzed(p_ptr->paralyzed + randint0(10) + 10)) + { + ident = TRUE; + } + } + break; + } + + case SV_FOOD_WEAKNESS: + { + take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_STR); + ident = TRUE; + break; + } + + case SV_FOOD_SICKNESS: + { + take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_CON); + ident = TRUE; + break; + } + + case SV_FOOD_STUPIDITY: + { + take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_INT); + ident = TRUE; + break; + } + + case SV_FOOD_NAIVETY: + { + take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_WIS); + ident = TRUE; + break; + } + + case SV_FOOD_UNHEALTH: + { + take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_CON); + ident = TRUE; + break; + } + + case SV_FOOD_DISEASE: + { + take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1); + (void)do_dec_stat(A_STR); + ident = TRUE; + break; + } + + case SV_FOOD_CURE_POISON: + { + if (set_poisoned(0)) ident = TRUE; + break; + } + + case SV_FOOD_CURE_BLINDNESS: + { + if (set_blind(0)) ident = TRUE; + break; + } + + case SV_FOOD_CURE_PARANOIA: + { + if (set_afraid(0)) ident = TRUE; + break; + } + + case SV_FOOD_CURE_CONFUSION: + { + if (set_confused(0)) ident = TRUE; + break; + } + + case SV_FOOD_CURE_SERIOUS: + { + ident = cure_serious_wounds(4, 8); + break; + } + + case SV_FOOD_RESTORE_STR: + { + if (do_res_stat(A_STR)) ident = TRUE; + break; + } + + case SV_FOOD_RESTORE_CON: + { + if (do_res_stat(A_CON)) ident = TRUE; + break; + } + + case SV_FOOD_RESTORING: + { + ident = restore_all_status(); + break; + } + + +#ifdef JP + /* それぞれの食べ物の感想をオリジナルより細かく表現 */ + case SV_FOOD_BISCUIT: + { + msg_print("甘くてサクサクしてとてもおいしい。"); + ident = TRUE; + break; + } + + case SV_FOOD_JERKY: + { + msg_print("歯ごたえがあっておいしい。"); + ident = TRUE; + break; + } + + case SV_FOOD_SLIME_MOLD: + { + msg_print("これはなんとも形容しがたい味だ。"); + ident = TRUE; + break; + } + + case SV_FOOD_RATION: + { + msg_print("これはおいしい。"); + ident = TRUE; + break; + } +#else + case SV_FOOD_RATION: + case SV_FOOD_BISCUIT: + case SV_FOOD_JERKY: + case SV_FOOD_SLIME_MOLD: + { + msg_print("That tastes good."); + ident = TRUE; + break; + } +#endif + + + case SV_FOOD_WAYBREAD: + { + msg_print(_("これはひじょうに美味だ。", "That tastes good.")); + (void)set_poisoned(0); + (void)hp_player(damroll(4, 8)); + ident = TRUE; + break; + } + +#ifdef JP + case SV_FOOD_PINT_OF_ALE: + { + msg_print("のどごし爽やかだ。"); + ident = TRUE; + break; + } + + case SV_FOOD_PINT_OF_WINE: + { + msg_print("That tastes good."); + ident = TRUE; + break; + } +#else + case SV_FOOD_PINT_OF_ALE: + case SV_FOOD_PINT_OF_WINE: + { + msg_print("That tastes good."); + ident = TRUE; + break; + } +#endif + + } + } + p_ptr->update |= (PU_COMBINE | PU_REORDER); + + if (!(object_is_aware(o_ptr))) + { + chg_virtue(V_KNOWLEDGE, -1); + chg_virtue(V_PATIENCE, -1); + chg_virtue(V_CHANCE, 1); + } + + /* We have tried it */ + if (o_ptr->tval == TV_FOOD) object_tried(o_ptr); + + /* The player is now aware of the object */ + if (ident && !object_is_aware(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Food can feed the player */ + if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) + { + /* Reduced nutritional benefit */ + (void)set_food(p_ptr->food + (o_ptr->pval / 10)); + msg_print(_("あなたのような者にとって食糧など僅かな栄養にしかならない。", + "Mere victuals hold scant sustenance for a being such as yourself.")); + + if (p_ptr->food < PY_FOOD_ALERT) /* Hungry */ + msg_print(_("あなたの飢えは新鮮な血によってのみ満たされる!", + "Your hunger can only be satisfied with fresh blood!")); + } + else if ((prace_is_(RACE_SKELETON) || + prace_is_(RACE_GOLEM) || + prace_is_(RACE_ZOMBIE) || + prace_is_(RACE_SPECTRE)) && + (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) + { + concptr staff; + + if (o_ptr->tval == TV_STAFF && + (item < 0) && (o_ptr->number > 1)) + { + msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs.")); + return; + } + staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand"); + + /* "Eat" charges */ + if (o_ptr->pval == 0) + { + msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff); + o_ptr->ident |= (IDENT_EMPTY); + p_ptr->update |= (PU_COMBINE | PU_REORDER); + p_ptr->window |= (PW_INVEN); + + return; + } + msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff); + + /* Use a single charge */ + o_ptr->pval--; + + /* Eat a charge */ + set_food(p_ptr->food + 5000); + + /* XXX Hack -- unstack if necessary */ + if (o_ptr->tval == TV_STAFF && + (item >= 0) && (o_ptr->number > 1)) + { + object_type forge; + object_type *q_ptr; + q_ptr = &forge; + + /* Obtain a local object */ + object_copy(q_ptr, o_ptr); + + /* Modify quantity */ + q_ptr->number = 1; + + /* Restore the charges */ + o_ptr->pval++; + + /* Unstack the used item */ + o_ptr->number--; + p_ptr->total_weight -= q_ptr->weight; + item = inven_carry(q_ptr); + + msg_format(_("杖をまとめなおした。", "You unstack your staff.")); + } + + /* Describe charges in the pack */ + if (item >= 0) + { + inven_item_charges(item); + } + + /* Describe charges on the floor */ + else + { + floor_item_charges(0 - item); + } + + p_ptr->window |= (PW_INVEN | PW_EQUIP); + + /* Don't eat a staff/wand itself */ + return; + } + else if ((prace_is_(RACE_DEMON) || + (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON)) && + (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE && + my_strchr("pht", r_info[o_ptr->pval].d_char))) + { + /* Drain vitality of humanoids */ + GAME_TEXT o_name[MAX_NLEN]; + object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); + msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%^s is burnt to ashes. You absorb its vitality!"), o_name); + (void)set_food(PY_FOOD_MAX - 1); + } + else if (prace_is_(RACE_SKELETON)) + { +#if 0 + if (o_ptr->tval == TV_SKELETON || + (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON)) + { + msg_print(_("あなたは骨で自分の体を補った。", "Your body absorbs the bone.")); + set_food(p_ptr->food + 5000); + } + else +#endif + + if (!((o_ptr->sval == SV_FOOD_WAYBREAD) || + (o_ptr->sval < SV_FOOD_BISCUIT))) + { + object_type forge; + object_type *q_ptr = &forge; + + msg_print(_("食べ物がアゴを素通りして落ちた!", "The food falls through your jaws!")); + object_prep(q_ptr, lookup_kind(o_ptr->tval, o_ptr->sval)); + + /* Drop the object from heaven */ + (void)drop_near(q_ptr, -1, p_ptr->y, p_ptr->x); + } + else + { + msg_print(_("食べ物がアゴを素通りして落ち、消えた!", "The food falls through your jaws and vanishes!")); + } + } + else if (prace_is_(RACE_GOLEM) || + prace_is_(RACE_ZOMBIE) || + prace_is_(RACE_ENT) || + prace_is_(RACE_DEMON) || + prace_is_(RACE_ANDROID) || + prace_is_(RACE_SPECTRE) || + (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING)) + { + msg_print(_("生者の食物はあなたにとってほとんど栄養にならない。", "The food of mortals is poor sustenance for you.")); + set_food(p_ptr->food + ((o_ptr->pval) / 20)); + } + else if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD) + { + /* Waybread is always fully satisfying. */ + set_food(MAX(p_ptr->food, PY_FOOD_MAX - 1)); + } + else + { + /* Food can feed the player */ + (void)set_food(p_ptr->food + o_ptr->pval); + } + + /* Destroy a food in the pack */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy a food on the floor */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } +} + + +/*! + * @brief 食料を食べるコマンドのメインルーチン / + * Eat some food (from the pack or floor) + * @return なし + */ +void do_cmd_eat_food(void) +{ + OBJECT_IDX item; + concptr q, s; + + if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) + { + set_action(ACTION_NONE); + } + + /* Restrict choices to food */ + item_tester_hook = item_tester_hook_eatable; + + q = _("どれを食べますか? ", "Eat which item? "); + s = _("食べ物がない。", "You have nothing to eat."); + + if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + /* Eat the object */ + do_cmd_eat_food_aux(item); +} + diff --git a/src/cmd-eat.h b/src/cmd-eat.h index bcbea340c..50df11aed 100644 --- a/src/cmd-eat.h +++ b/src/cmd-eat.h @@ -1,3 +1,3 @@ - -extern void do_cmd_eat_food(void); -extern void do_cmd_eat_food_aux(INVENTORY_IDX item); + +extern void do_cmd_eat_food(void); +extern void do_cmd_eat_food_aux(INVENTORY_IDX item); diff --git a/src/cmd-item.h b/src/cmd-item.h index 539cd6e40..e205349a5 100644 --- a/src/cmd-item.h +++ b/src/cmd-item.h @@ -1,17 +1,17 @@ -/* cmd3-item.h */ - -extern void do_cmd_inven(void); -extern void do_cmd_equip(void); -extern void do_cmd_wield(void); -extern void do_cmd_takeoff(void); -extern void do_cmd_drop(void); -extern void do_cmd_destroy(void); -extern void do_cmd_observe(void); -extern void do_cmd_uninscribe(void); -extern void do_cmd_inscribe(void); -extern void do_cmd_refill(void); -extern void do_cmd_target(void); -extern void do_cmd_look(void); -extern void do_cmd_locate(void); -extern void do_cmd_query_symbol(void); +/* cmd3-item.h */ + +extern void do_cmd_inven(void); +extern void do_cmd_equip(void); +extern void do_cmd_wield(void); +extern void do_cmd_takeoff(void); +extern void do_cmd_drop(void); +extern void do_cmd_destroy(void); +extern void do_cmd_observe(void); +extern void do_cmd_uninscribe(void); +extern void do_cmd_inscribe(void); +extern void do_cmd_refill(void); +extern void do_cmd_target(void); +extern void do_cmd_look(void); +extern void do_cmd_locate(void); +extern void do_cmd_query_symbol(void); extern void do_cmd_use(void); \ No newline at end of file diff --git a/src/cmd-pet.h b/src/cmd-pet.h index 9b7c075f2..de0c16423 100644 --- a/src/cmd-pet.h +++ b/src/cmd-pet.h @@ -1,9 +1,9 @@ -extern bool do_riding(bool force); -extern void check_pets_num_and_align(monster_type *m_ptr, bool inc); -extern int calculate_upkeep(void); -extern void do_cmd_pet_dismiss(void); -extern void do_cmd_pet(void); -extern bool player_can_ride_aux(cave_type *c_ptr, bool now_riding); -extern bool rakuba(HIT_POINT dam, bool force); - - +extern bool do_riding(bool force); +extern void check_pets_num_and_align(monster_type *m_ptr, bool inc); +extern int calculate_upkeep(void); +extern void do_cmd_pet_dismiss(void); +extern void do_cmd_pet(void); +extern bool player_can_ride_aux(cave_type *c_ptr, bool now_riding); +extern bool rakuba(HIT_POINT dam, bool force); + + diff --git a/src/cmd-quaff.c b/src/cmd-quaff.c index 5a4d6950d..c4586ae27 100644 --- a/src/cmd-quaff.c +++ b/src/cmd-quaff.c @@ -1,611 +1,611 @@ -/*! - * @file cmd-quaff.c - * @brief プレイヤーの飲むコマンド実装 - * @date 2018/09/07 - * @details - * cmd6.cより分離。 - */ - -#include "angband.h" -#include "selfinfo.h" -#include "object-hook.h" -#include "mutation.h" -#include "avatar.h" -#include "spells-status.h" -#include "realm-hex.h" - -/*! - * @brief 薬を飲むコマンドのサブルーチン / - * Quaff a potion (from the pack or the floor) - * @param item 飲む薬オブジェクトの所持品ID - * @return なし - */ -void do_cmd_quaff_potion_aux(INVENTORY_IDX item) -{ - bool ident; - DEPTH lev; - object_type *o_ptr; - object_type forge; - object_type *q_ptr; - - - if (p_ptr->timewalk) - { - if (flush_failure) flush(); - msg_print(_("瓶から水が流れ出てこない!", "The potion doesn't flow out from a bottle.")); - - sound(SOUND_FAIL); - return; - } - - if (music_singing_any()) stop_singing(); - if (hex_spelling_any()) - { - if (!hex_spelling(HEX_INHAIL)) stop_hex_spell_all(); - } - - /* Get the item (in the pack) */ - if (item >= 0) - { - o_ptr = &inventory[item]; - } - - /* Get the item (on the floor) */ - else - { - o_ptr = &o_list[0 - item]; - } - q_ptr = &forge; - - /* Obtain a local object */ - object_copy(q_ptr, o_ptr); - - /* Single object */ - q_ptr->number = 1; - - /* Reduce and describe inventory */ - if (item >= 0) - { - inven_item_increase(item, -1); - inven_item_describe(item); - inven_item_optimize(item); - } - - /* Reduce and describe floor item */ - else - { - floor_item_increase(0 - item, -1); - floor_item_describe(0 - item); - floor_item_optimize(0 - item); - } - - sound(SOUND_QUAFF); - - - /* Not identified yet */ - ident = FALSE; - - /* Object level */ - lev = k_info[q_ptr->k_idx].level; - - /* Analyze the potion */ - if (q_ptr->tval == TV_POTION) - { - switch (q_ptr->sval) - { - /* 飲みごたえをオリジナルより細かく表現 */ - case SV_POTION_WATER: - msg_print(_("口の中がさっぱりした。", "")); - msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); - ident = TRUE; - break; - - case SV_POTION_APPLE_JUICE: - msg_print(_("甘くてサッパリとしていて、とてもおいしい。", "")); - msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); - ident = TRUE; - break; - - case SV_POTION_SLIME_MOLD: - msg_print(_("なんとも不気味な味だ。", "")); - msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); - ident = TRUE; - break; - - case SV_POTION_SLOWNESS: - if (set_slow(randint1(25) + 15, FALSE)) ident = TRUE; - break; - - case SV_POTION_SALT_WATER: - msg_print(_("うぇ!思わず吐いてしまった。", "The potion makes you vomit!")); - - if (!(prace_is_(RACE_GOLEM) || - prace_is_(RACE_ZOMBIE) || - prace_is_(RACE_DEMON) || - prace_is_(RACE_ANDROID) || - prace_is_(RACE_SPECTRE) || - (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING))) - { - /* Only living creatures get thirsty */ - (void)set_food(PY_FOOD_STARVE - 1); - } - - (void)set_poisoned(0); - (void)set_paralyzed(p_ptr->paralyzed + 4); - ident = TRUE; - break; - - case SV_POTION_POISON: - if (!(p_ptr->resist_pois || IS_OPPOSE_POIS())) - { - if (set_poisoned(p_ptr->poisoned + randint0(15) + 10)) - { - ident = TRUE; - } - } - break; - - case SV_POTION_BLINDNESS: - if (!p_ptr->resist_blind) - { - if (set_blind(p_ptr->blind + randint0(100) + 100)) - { - ident = TRUE; - } - } - break; - - case SV_POTION_BOOZE: - ident = booze(p_ptr); - break; - - case SV_POTION_SLEEP: - if (!p_ptr->free_act) - { - msg_print(_("あなたは眠ってしまった。", "You fall asleep.")); - - if (ironman_nightmare) - { - msg_print(_("恐ろしい光景が頭に浮かんできた。", "A horrible vision enters your mind.")); - - /* Have some nightmares */ - sanity_blast(NULL, FALSE); - } - if (set_paralyzed(p_ptr->paralyzed + randint0(4) + 4)) - { - ident = TRUE; - } - } - break; - - case SV_POTION_LOSE_MEMORIES: - if (!p_ptr->hold_exp && (p_ptr->exp > 0)) - { - msg_print(_("過去の記憶が薄れていく気がする。", "You feel your memories fade.")); - chg_virtue(V_KNOWLEDGE, -5); - - lose_exp(p_ptr->exp / 4); - ident = TRUE; - } - break; - - case SV_POTION_RUINATION: - msg_print(_("身も心も弱ってきて、精気が抜けていくようだ。", "Your nerves and muscles feel weak and lifeless!")); - take_hit(DAMAGE_LOSELIFE, damroll(10, 10), _("破滅の薬", "a potion of Ruination"), -1); - - (void)dec_stat(A_DEX, 25, TRUE); - (void)dec_stat(A_WIS, 25, TRUE); - (void)dec_stat(A_CON, 25, TRUE); - (void)dec_stat(A_STR, 25, TRUE); - (void)dec_stat(A_CHR, 25, TRUE); - (void)dec_stat(A_INT, 25, TRUE); - ident = TRUE; - break; - - case SV_POTION_DEC_STR: - if (do_dec_stat(A_STR)) ident = TRUE; - break; - - case SV_POTION_DEC_INT: - if (do_dec_stat(A_INT)) ident = TRUE; - break; - - case SV_POTION_DEC_WIS: - if (do_dec_stat(A_WIS)) ident = TRUE; - break; - - case SV_POTION_DEC_DEX: - if (do_dec_stat(A_DEX)) ident = TRUE; - break; - - case SV_POTION_DEC_CON: - if (do_dec_stat(A_CON)) ident = TRUE; - break; - - case SV_POTION_DEC_CHR: - if (do_dec_stat(A_CHR)) ident = TRUE; - break; - - case SV_POTION_DETONATIONS: - ident = detonation(p_ptr); - break; - - case SV_POTION_DEATH: - chg_virtue(V_VITALITY, -1); - chg_virtue(V_UNLIFE, 5); - msg_print(_("死の予感が体中を駆けめぐった。", "A feeling of Death flows through your body.")); - take_hit(DAMAGE_LOSELIFE, 5000, _("死の薬", "a potion of Death"), -1); - ident = TRUE; - break; - - case SV_POTION_INFRAVISION: - if (set_tim_infra(p_ptr->tim_infra + 100 + randint1(100), FALSE)) - { - ident = TRUE; - } - break; - - case SV_POTION_DETECT_INVIS: - if (set_tim_invis(p_ptr->tim_invis + 12 + randint1(12), FALSE)) - { - ident = TRUE; - } - break; - - case SV_POTION_SLOW_POISON: - if (set_poisoned(p_ptr->poisoned / 2)) ident = TRUE; - break; - - case SV_POTION_CURE_POISON: - if (set_poisoned(0)) ident = TRUE; - break; - - case SV_POTION_BOLDNESS: - if (set_afraid(0)) ident = TRUE; - break; - - case SV_POTION_SPEED: - if (!p_ptr->fast) - { - if (set_fast(randint1(25) + 15, FALSE)) ident = TRUE; - } - else - { - (void)set_fast(p_ptr->fast + 5, FALSE); - } - break; - - case SV_POTION_RESIST_HEAT: - if (set_oppose_fire(p_ptr->oppose_fire + randint1(10) + 10, FALSE)) - { - ident = TRUE; - } - break; - - case SV_POTION_RESIST_COLD: - if (set_oppose_cold(p_ptr->oppose_cold + randint1(10) + 10, FALSE)) - { - ident = TRUE; - } - break; - - case SV_POTION_HEROISM: - ident = heroism(25); - break; - - case SV_POTION_BESERK_STRENGTH: - ident = berserk(randint1(25) + 25); - break; - - case SV_POTION_CURE_LIGHT: - ident = cure_light_wounds(2, 8); - break; - - case SV_POTION_CURE_SERIOUS: - ident = cure_serious_wounds(4, 8); - break; - - case SV_POTION_CURE_CRITICAL: - ident = cure_critical_wounds(damroll(6, 8)); - break; - - case SV_POTION_HEALING: - ident = cure_critical_wounds(300); - break; - - case SV_POTION_STAR_HEALING: - ident = cure_critical_wounds(1200); - break; - - case SV_POTION_LIFE: - ident = life_stream(TRUE, TRUE); - break; - - case SV_POTION_RESTORE_MANA: - ident = restore_mana(TRUE); - break; - - case SV_POTION_RESTORE_EXP: - if (restore_level()) ident = TRUE; - break; - - case SV_POTION_RES_STR: - if (do_res_stat(A_STR)) ident = TRUE; - break; - - case SV_POTION_RES_INT: - if (do_res_stat(A_INT)) ident = TRUE; - break; - - case SV_POTION_RES_WIS: - if (do_res_stat(A_WIS)) ident = TRUE; - break; - - case SV_POTION_RES_DEX: - if (do_res_stat(A_DEX)) ident = TRUE; - break; - - case SV_POTION_RES_CON: - if (do_res_stat(A_CON)) ident = TRUE; - break; - - case SV_POTION_RES_CHR: - if (do_res_stat(A_CHR)) ident = TRUE; - break; - - case SV_POTION_INC_STR: - if (do_inc_stat(A_STR)) ident = TRUE; - break; - - case SV_POTION_INC_INT: - if (do_inc_stat(A_INT)) ident = TRUE; - break; - - case SV_POTION_INC_WIS: - if (do_inc_stat(A_WIS)) ident = TRUE; - break; - - case SV_POTION_INC_DEX: - if (do_inc_stat(A_DEX)) ident = TRUE; - break; - - case SV_POTION_INC_CON: - if (do_inc_stat(A_CON)) ident = TRUE; - break; - - case SV_POTION_INC_CHR: - if (do_inc_stat(A_CHR)) ident = TRUE; - break; - - case SV_POTION_AUGMENTATION: - if (do_inc_stat(A_STR)) ident = TRUE; - if (do_inc_stat(A_INT)) ident = TRUE; - if (do_inc_stat(A_WIS)) ident = TRUE; - if (do_inc_stat(A_DEX)) ident = TRUE; - if (do_inc_stat(A_CON)) ident = TRUE; - if (do_inc_stat(A_CHR)) ident = TRUE; - break; - - case SV_POTION_ENLIGHTENMENT: - msg_print(_("自分の置かれている状況が脳裏に浮かんできた...", "An image of your surroundings forms in your mind...")); - chg_virtue(V_KNOWLEDGE, 1); - chg_virtue(V_ENLIGHTEN, 1); - wiz_lite(FALSE); - ident = TRUE; - break; - - case SV_POTION_STAR_ENLIGHTENMENT: - msg_print(_("更なる啓蒙を感じた...", "You begin to feel more enlightened...")); - chg_virtue(V_KNOWLEDGE, 1); - chg_virtue(V_ENLIGHTEN, 2); - msg_print(NULL); - wiz_lite(FALSE); - (void)do_inc_stat(A_INT); - (void)do_inc_stat(A_WIS); - (void)detect_traps(DETECT_RAD_DEFAULT, TRUE); - (void)detect_doors(DETECT_RAD_DEFAULT); - (void)detect_stairs(DETECT_RAD_DEFAULT); - (void)detect_treasure(DETECT_RAD_DEFAULT); - (void)detect_objects_gold(DETECT_RAD_DEFAULT); - (void)detect_objects_normal(DETECT_RAD_DEFAULT); - identify_pack(); - self_knowledge(); - ident = TRUE; - break; - - case SV_POTION_SELF_KNOWLEDGE: - msg_print(_("自分自身のことが少しは分かった気がする...", "You begin to know yourself a little better...")); - msg_print(NULL); - self_knowledge(); - ident = TRUE; - break; - - case SV_POTION_EXPERIENCE: - if (p_ptr->prace == RACE_ANDROID) break; - chg_virtue(V_ENLIGHTEN, 1); - if (p_ptr->exp < PY_MAX_EXP) - { - s32b ee = (p_ptr->exp / 2) + 10; - if (ee > 100000L) ee = 100000L; - msg_print(_("更に経験を積んだような気がする。", "You feel more experienced.")); - gain_exp(ee); - ident = TRUE; - } - break; - - case SV_POTION_RESISTANCE: - (void)set_oppose_acid(p_ptr->oppose_acid + randint1(20) + 20, FALSE); - (void)set_oppose_elec(p_ptr->oppose_elec + randint1(20) + 20, FALSE); - (void)set_oppose_fire(p_ptr->oppose_fire + randint1(20) + 20, FALSE); - (void)set_oppose_cold(p_ptr->oppose_cold + randint1(20) + 20, FALSE); - (void)set_oppose_pois(p_ptr->oppose_pois + randint1(20) + 20, FALSE); - ident = TRUE; - break; - - case SV_POTION_CURING: - if (true_healing(50)) ident = TRUE; - break; - - case SV_POTION_INVULNERABILITY: - (void)set_invuln(p_ptr->invuln + randint1(4) + 4, FALSE); - ident = TRUE; - break; - - case SV_POTION_NEW_LIFE: - roll_hitdice(0L); - get_max_stats(); - p_ptr->update |= PU_BONUS; - lose_all_mutations(); - ident = TRUE; - break; - - case SV_POTION_NEO_TSUYOSHI: - (void)set_image(0); - (void)set_tsuyoshi(p_ptr->tsuyoshi + randint1(100) + 100, FALSE); - ident = TRUE; - break; - - case SV_POTION_TSUYOSHI: - msg_print(_("「オクレ兄さん!」", "Brother OKURE!")); - msg_print(NULL); - p_ptr->tsuyoshi = 1; - (void)set_tsuyoshi(0, TRUE); - if (!p_ptr->resist_chaos) - { - (void)set_image(50 + randint1(50)); - } - ident = TRUE; - break; - - case SV_POTION_POLYMORPH: - if ((p_ptr->muta1 || p_ptr->muta2 || p_ptr->muta3) && one_in_(23)) - { - lose_all_mutations(); - } - else - { - do - { - if (one_in_(2)) - { - if(gain_random_mutation(0)) ident = TRUE; - } - else if (lose_mutation(0)) ident = TRUE; - } while(!ident || one_in_(2)); - } - break; - } - } - - if (prace_is_(RACE_SKELETON)) - { - msg_print(_("液体の一部はあなたのアゴを素通りして落ちた!", "Some of the fluid falls through your jaws!")); - (void)potion_smash_effect(0, p_ptr->y, p_ptr->x, q_ptr->k_idx); - } - p_ptr->update |= (PU_COMBINE | PU_REORDER); - - if (!(object_is_aware(q_ptr))) - { - chg_virtue(V_PATIENCE, -1); - chg_virtue(V_CHANCE, 1); - chg_virtue(V_KNOWLEDGE, -1); - } - - /* The item has been tried */ - object_tried(q_ptr); - - /* An identification was made */ - if (ident && !object_is_aware(q_ptr)) - { - object_aware(q_ptr); - gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); - } - - p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); - - /* Potions can feed the player */ - switch (p_ptr->mimic_form) - { - case MIMIC_NONE: - switch (p_ptr->prace) - { - case RACE_VAMPIRE: - (void)set_food(p_ptr->food + (q_ptr->pval / 10)); - break; - case RACE_SKELETON: - /* Do nothing */ - break; - case RACE_GOLEM: - case RACE_ZOMBIE: - case RACE_DEMON: - case RACE_SPECTRE: - set_food(p_ptr->food + ((q_ptr->pval) / 20)); - break; - case RACE_ANDROID: - if (q_ptr->tval == TV_FLASK) - { - msg_print(_("オイルを補給した。", "You replenish yourself with the oil.")); - set_food(p_ptr->food + 5000); - } - else - { - set_food(p_ptr->food + ((q_ptr->pval) / 20)); - } - break; - case RACE_ENT: - msg_print(_("水分を取り込んだ。", "You are moistened.")); - set_food(MIN(p_ptr->food + q_ptr->pval + MAX(0, q_ptr->pval * 10) + 2000, PY_FOOD_MAX - 1)); - break; - default: - (void)set_food(p_ptr->food + q_ptr->pval); - break; - } - break; - case MIMIC_DEMON: - case MIMIC_DEMON_LORD: - set_food(p_ptr->food + ((q_ptr->pval) / 20)); - break; - case MIMIC_VAMPIRE: - (void)set_food(p_ptr->food + (q_ptr->pval / 10)); - break; - default: - (void)set_food(p_ptr->food + q_ptr->pval); - break; - } -} - - - -/*! - * @brief 薬を飲むコマンドのメインルーチン / - * Quaff some potion (from the pack or floor) - * @return なし - */ -void do_cmd_quaff_potion(void) -{ - OBJECT_IDX item; - concptr q, s; - - if (p_ptr->wild_mode) - { - return; - } - - if (cmd_limit_arena(p_ptr)) return; - - if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) - { - set_action(ACTION_NONE); - } - - /* Restrict choices to potions */ - item_tester_hook = item_tester_hook_quaff; - - q = _("どの薬を飲みますか? ", "Quaff which potion? "); - s = _("飲める薬がない。", "You have no potions to quaff."); - - if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; - - /* Quaff the potion */ - do_cmd_quaff_potion_aux(item); -} +/*! + * @file cmd-quaff.c + * @brief プレイヤーの飲むコマンド実装 + * @date 2018/09/07 + * @details + * cmd6.cより分離。 + */ + +#include "angband.h" +#include "selfinfo.h" +#include "object-hook.h" +#include "mutation.h" +#include "avatar.h" +#include "spells-status.h" +#include "realm-hex.h" + +/*! + * @brief 薬を飲むコマンドのサブルーチン / + * Quaff a potion (from the pack or the floor) + * @param item 飲む薬オブジェクトの所持品ID + * @return なし + */ +void do_cmd_quaff_potion_aux(INVENTORY_IDX item) +{ + bool ident; + DEPTH lev; + object_type *o_ptr; + object_type forge; + object_type *q_ptr; + + + if (p_ptr->timewalk) + { + if (flush_failure) flush(); + msg_print(_("瓶から水が流れ出てこない!", "The potion doesn't flow out from a bottle.")); + + sound(SOUND_FAIL); + return; + } + + if (music_singing_any()) stop_singing(); + if (hex_spelling_any()) + { + if (!hex_spelling(HEX_INHAIL)) stop_hex_spell_all(); + } + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + q_ptr = &forge; + + /* Obtain a local object */ + object_copy(q_ptr, o_ptr); + + /* Single object */ + q_ptr->number = 1; + + /* Reduce and describe inventory */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Reduce and describe floor item */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } + + sound(SOUND_QUAFF); + + + /* Not identified yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[q_ptr->k_idx].level; + + /* Analyze the potion */ + if (q_ptr->tval == TV_POTION) + { + switch (q_ptr->sval) + { + /* 飲みごたえをオリジナルより細かく表現 */ + case SV_POTION_WATER: + msg_print(_("口の中がさっぱりした。", "")); + msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); + ident = TRUE; + break; + + case SV_POTION_APPLE_JUICE: + msg_print(_("甘くてサッパリとしていて、とてもおいしい。", "")); + msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); + ident = TRUE; + break; + + case SV_POTION_SLIME_MOLD: + msg_print(_("なんとも不気味な味だ。", "")); + msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty.")); + ident = TRUE; + break; + + case SV_POTION_SLOWNESS: + if (set_slow(randint1(25) + 15, FALSE)) ident = TRUE; + break; + + case SV_POTION_SALT_WATER: + msg_print(_("うぇ!思わず吐いてしまった。", "The potion makes you vomit!")); + + if (!(prace_is_(RACE_GOLEM) || + prace_is_(RACE_ZOMBIE) || + prace_is_(RACE_DEMON) || + prace_is_(RACE_ANDROID) || + prace_is_(RACE_SPECTRE) || + (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING))) + { + /* Only living creatures get thirsty */ + (void)set_food(PY_FOOD_STARVE - 1); + } + + (void)set_poisoned(0); + (void)set_paralyzed(p_ptr->paralyzed + 4); + ident = TRUE; + break; + + case SV_POTION_POISON: + if (!(p_ptr->resist_pois || IS_OPPOSE_POIS())) + { + if (set_poisoned(p_ptr->poisoned + randint0(15) + 10)) + { + ident = TRUE; + } + } + break; + + case SV_POTION_BLINDNESS: + if (!p_ptr->resist_blind) + { + if (set_blind(p_ptr->blind + randint0(100) + 100)) + { + ident = TRUE; + } + } + break; + + case SV_POTION_BOOZE: + ident = booze(p_ptr); + break; + + case SV_POTION_SLEEP: + if (!p_ptr->free_act) + { + msg_print(_("あなたは眠ってしまった。", "You fall asleep.")); + + if (ironman_nightmare) + { + msg_print(_("恐ろしい光景が頭に浮かんできた。", "A horrible vision enters your mind.")); + + /* Have some nightmares */ + sanity_blast(NULL, FALSE); + } + if (set_paralyzed(p_ptr->paralyzed + randint0(4) + 4)) + { + ident = TRUE; + } + } + break; + + case SV_POTION_LOSE_MEMORIES: + if (!p_ptr->hold_exp && (p_ptr->exp > 0)) + { + msg_print(_("過去の記憶が薄れていく気がする。", "You feel your memories fade.")); + chg_virtue(V_KNOWLEDGE, -5); + + lose_exp(p_ptr->exp / 4); + ident = TRUE; + } + break; + + case SV_POTION_RUINATION: + msg_print(_("身も心も弱ってきて、精気が抜けていくようだ。", "Your nerves and muscles feel weak and lifeless!")); + take_hit(DAMAGE_LOSELIFE, damroll(10, 10), _("破滅の薬", "a potion of Ruination"), -1); + + (void)dec_stat(A_DEX, 25, TRUE); + (void)dec_stat(A_WIS, 25, TRUE); + (void)dec_stat(A_CON, 25, TRUE); + (void)dec_stat(A_STR, 25, TRUE); + (void)dec_stat(A_CHR, 25, TRUE); + (void)dec_stat(A_INT, 25, TRUE); + ident = TRUE; + break; + + case SV_POTION_DEC_STR: + if (do_dec_stat(A_STR)) ident = TRUE; + break; + + case SV_POTION_DEC_INT: + if (do_dec_stat(A_INT)) ident = TRUE; + break; + + case SV_POTION_DEC_WIS: + if (do_dec_stat(A_WIS)) ident = TRUE; + break; + + case SV_POTION_DEC_DEX: + if (do_dec_stat(A_DEX)) ident = TRUE; + break; + + case SV_POTION_DEC_CON: + if (do_dec_stat(A_CON)) ident = TRUE; + break; + + case SV_POTION_DEC_CHR: + if (do_dec_stat(A_CHR)) ident = TRUE; + break; + + case SV_POTION_DETONATIONS: + ident = detonation(p_ptr); + break; + + case SV_POTION_DEATH: + chg_virtue(V_VITALITY, -1); + chg_virtue(V_UNLIFE, 5); + msg_print(_("死の予感が体中を駆けめぐった。", "A feeling of Death flows through your body.")); + take_hit(DAMAGE_LOSELIFE, 5000, _("死の薬", "a potion of Death"), -1); + ident = TRUE; + break; + + case SV_POTION_INFRAVISION: + if (set_tim_infra(p_ptr->tim_infra + 100 + randint1(100), FALSE)) + { + ident = TRUE; + } + break; + + case SV_POTION_DETECT_INVIS: + if (set_tim_invis(p_ptr->tim_invis + 12 + randint1(12), FALSE)) + { + ident = TRUE; + } + break; + + case SV_POTION_SLOW_POISON: + if (set_poisoned(p_ptr->poisoned / 2)) ident = TRUE; + break; + + case SV_POTION_CURE_POISON: + if (set_poisoned(0)) ident = TRUE; + break; + + case SV_POTION_BOLDNESS: + if (set_afraid(0)) ident = TRUE; + break; + + case SV_POTION_SPEED: + if (!p_ptr->fast) + { + if (set_fast(randint1(25) + 15, FALSE)) ident = TRUE; + } + else + { + (void)set_fast(p_ptr->fast + 5, FALSE); + } + break; + + case SV_POTION_RESIST_HEAT: + if (set_oppose_fire(p_ptr->oppose_fire + randint1(10) + 10, FALSE)) + { + ident = TRUE; + } + break; + + case SV_POTION_RESIST_COLD: + if (set_oppose_cold(p_ptr->oppose_cold + randint1(10) + 10, FALSE)) + { + ident = TRUE; + } + break; + + case SV_POTION_HEROISM: + ident = heroism(25); + break; + + case SV_POTION_BESERK_STRENGTH: + ident = berserk(randint1(25) + 25); + break; + + case SV_POTION_CURE_LIGHT: + ident = cure_light_wounds(2, 8); + break; + + case SV_POTION_CURE_SERIOUS: + ident = cure_serious_wounds(4, 8); + break; + + case SV_POTION_CURE_CRITICAL: + ident = cure_critical_wounds(damroll(6, 8)); + break; + + case SV_POTION_HEALING: + ident = cure_critical_wounds(300); + break; + + case SV_POTION_STAR_HEALING: + ident = cure_critical_wounds(1200); + break; + + case SV_POTION_LIFE: + ident = life_stream(TRUE, TRUE); + break; + + case SV_POTION_RESTORE_MANA: + ident = restore_mana(TRUE); + break; + + case SV_POTION_RESTORE_EXP: + if (restore_level()) ident = TRUE; + break; + + case SV_POTION_RES_STR: + if (do_res_stat(A_STR)) ident = TRUE; + break; + + case SV_POTION_RES_INT: + if (do_res_stat(A_INT)) ident = TRUE; + break; + + case SV_POTION_RES_WIS: + if (do_res_stat(A_WIS)) ident = TRUE; + break; + + case SV_POTION_RES_DEX: + if (do_res_stat(A_DEX)) ident = TRUE; + break; + + case SV_POTION_RES_CON: + if (do_res_stat(A_CON)) ident = TRUE; + break; + + case SV_POTION_RES_CHR: + if (do_res_stat(A_CHR)) ident = TRUE; + break; + + case SV_POTION_INC_STR: + if (do_inc_stat(A_STR)) ident = TRUE; + break; + + case SV_POTION_INC_INT: + if (do_inc_stat(A_INT)) ident = TRUE; + break; + + case SV_POTION_INC_WIS: + if (do_inc_stat(A_WIS)) ident = TRUE; + break; + + case SV_POTION_INC_DEX: + if (do_inc_stat(A_DEX)) ident = TRUE; + break; + + case SV_POTION_INC_CON: + if (do_inc_stat(A_CON)) ident = TRUE; + break; + + case SV_POTION_INC_CHR: + if (do_inc_stat(A_CHR)) ident = TRUE; + break; + + case SV_POTION_AUGMENTATION: + if (do_inc_stat(A_STR)) ident = TRUE; + if (do_inc_stat(A_INT)) ident = TRUE; + if (do_inc_stat(A_WIS)) ident = TRUE; + if (do_inc_stat(A_DEX)) ident = TRUE; + if (do_inc_stat(A_CON)) ident = TRUE; + if (do_inc_stat(A_CHR)) ident = TRUE; + break; + + case SV_POTION_ENLIGHTENMENT: + msg_print(_("自分の置かれている状況が脳裏に浮かんできた...", "An image of your surroundings forms in your mind...")); + chg_virtue(V_KNOWLEDGE, 1); + chg_virtue(V_ENLIGHTEN, 1); + wiz_lite(FALSE); + ident = TRUE; + break; + + case SV_POTION_STAR_ENLIGHTENMENT: + msg_print(_("更なる啓蒙を感じた...", "You begin to feel more enlightened...")); + chg_virtue(V_KNOWLEDGE, 1); + chg_virtue(V_ENLIGHTEN, 2); + msg_print(NULL); + wiz_lite(FALSE); + (void)do_inc_stat(A_INT); + (void)do_inc_stat(A_WIS); + (void)detect_traps(DETECT_RAD_DEFAULT, TRUE); + (void)detect_doors(DETECT_RAD_DEFAULT); + (void)detect_stairs(DETECT_RAD_DEFAULT); + (void)detect_treasure(DETECT_RAD_DEFAULT); + (void)detect_objects_gold(DETECT_RAD_DEFAULT); + (void)detect_objects_normal(DETECT_RAD_DEFAULT); + identify_pack(); + self_knowledge(); + ident = TRUE; + break; + + case SV_POTION_SELF_KNOWLEDGE: + msg_print(_("自分自身のことが少しは分かった気がする...", "You begin to know yourself a little better...")); + msg_print(NULL); + self_knowledge(); + ident = TRUE; + break; + + case SV_POTION_EXPERIENCE: + if (p_ptr->prace == RACE_ANDROID) break; + chg_virtue(V_ENLIGHTEN, 1); + if (p_ptr->exp < PY_MAX_EXP) + { + s32b ee = (p_ptr->exp / 2) + 10; + if (ee > 100000L) ee = 100000L; + msg_print(_("更に経験を積んだような気がする。", "You feel more experienced.")); + gain_exp(ee); + ident = TRUE; + } + break; + + case SV_POTION_RESISTANCE: + (void)set_oppose_acid(p_ptr->oppose_acid + randint1(20) + 20, FALSE); + (void)set_oppose_elec(p_ptr->oppose_elec + randint1(20) + 20, FALSE); + (void)set_oppose_fire(p_ptr->oppose_fire + randint1(20) + 20, FALSE); + (void)set_oppose_cold(p_ptr->oppose_cold + randint1(20) + 20, FALSE); + (void)set_oppose_pois(p_ptr->oppose_pois + randint1(20) + 20, FALSE); + ident = TRUE; + break; + + case SV_POTION_CURING: + if (true_healing(50)) ident = TRUE; + break; + + case SV_POTION_INVULNERABILITY: + (void)set_invuln(p_ptr->invuln + randint1(4) + 4, FALSE); + ident = TRUE; + break; + + case SV_POTION_NEW_LIFE: + roll_hitdice(0L); + get_max_stats(); + p_ptr->update |= PU_BONUS; + lose_all_mutations(); + ident = TRUE; + break; + + case SV_POTION_NEO_TSUYOSHI: + (void)set_image(0); + (void)set_tsuyoshi(p_ptr->tsuyoshi + randint1(100) + 100, FALSE); + ident = TRUE; + break; + + case SV_POTION_TSUYOSHI: + msg_print(_("「オクレ兄さん!」", "Brother OKURE!")); + msg_print(NULL); + p_ptr->tsuyoshi = 1; + (void)set_tsuyoshi(0, TRUE); + if (!p_ptr->resist_chaos) + { + (void)set_image(50 + randint1(50)); + } + ident = TRUE; + break; + + case SV_POTION_POLYMORPH: + if ((p_ptr->muta1 || p_ptr->muta2 || p_ptr->muta3) && one_in_(23)) + { + lose_all_mutations(); + } + else + { + do + { + if (one_in_(2)) + { + if(gain_random_mutation(0)) ident = TRUE; + } + else if (lose_mutation(0)) ident = TRUE; + } while(!ident || one_in_(2)); + } + break; + } + } + + if (prace_is_(RACE_SKELETON)) + { + msg_print(_("液体の一部はあなたのアゴを素通りして落ちた!", "Some of the fluid falls through your jaws!")); + (void)potion_smash_effect(0, p_ptr->y, p_ptr->x, q_ptr->k_idx); + } + p_ptr->update |= (PU_COMBINE | PU_REORDER); + + if (!(object_is_aware(q_ptr))) + { + chg_virtue(V_PATIENCE, -1); + chg_virtue(V_CHANCE, 1); + chg_virtue(V_KNOWLEDGE, -1); + } + + /* The item has been tried */ + object_tried(q_ptr); + + /* An identification was made */ + if (ident && !object_is_aware(q_ptr)) + { + object_aware(q_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + /* Potions can feed the player */ + switch (p_ptr->mimic_form) + { + case MIMIC_NONE: + switch (p_ptr->prace) + { + case RACE_VAMPIRE: + (void)set_food(p_ptr->food + (q_ptr->pval / 10)); + break; + case RACE_SKELETON: + /* Do nothing */ + break; + case RACE_GOLEM: + case RACE_ZOMBIE: + case RACE_DEMON: + case RACE_SPECTRE: + set_food(p_ptr->food + ((q_ptr->pval) / 20)); + break; + case RACE_ANDROID: + if (q_ptr->tval == TV_FLASK) + { + msg_print(_("オイルを補給した。", "You replenish yourself with the oil.")); + set_food(p_ptr->food + 5000); + } + else + { + set_food(p_ptr->food + ((q_ptr->pval) / 20)); + } + break; + case RACE_ENT: + msg_print(_("水分を取り込んだ。", "You are moistened.")); + set_food(MIN(p_ptr->food + q_ptr->pval + MAX(0, q_ptr->pval * 10) + 2000, PY_FOOD_MAX - 1)); + break; + default: + (void)set_food(p_ptr->food + q_ptr->pval); + break; + } + break; + case MIMIC_DEMON: + case MIMIC_DEMON_LORD: + set_food(p_ptr->food + ((q_ptr->pval) / 20)); + break; + case MIMIC_VAMPIRE: + (void)set_food(p_ptr->food + (q_ptr->pval / 10)); + break; + default: + (void)set_food(p_ptr->food + q_ptr->pval); + break; + } +} + + + +/*! + * @brief 薬を飲むコマンドのメインルーチン / + * Quaff some potion (from the pack or floor) + * @return なし + */ +void do_cmd_quaff_potion(void) +{ + OBJECT_IDX item; + concptr q, s; + + if (p_ptr->wild_mode) + { + return; + } + + if (cmd_limit_arena(p_ptr)) return; + + if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) + { + set_action(ACTION_NONE); + } + + /* Restrict choices to potions */ + item_tester_hook = item_tester_hook_quaff; + + q = _("どの薬を飲みますか? ", "Quaff which potion? "); + s = _("飲める薬がない。", "You have no potions to quaff."); + + if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + /* Quaff the potion */ + do_cmd_quaff_potion_aux(item); +} diff --git a/src/cmd-quaff.h b/src/cmd-quaff.h index 08f9954ac..b797d93d3 100644 --- a/src/cmd-quaff.h +++ b/src/cmd-quaff.h @@ -1,4 +1,4 @@ - -extern void do_cmd_quaff_potion(void); -extern void do_cmd_quaff_potion_aux(INVENTORY_IDX item); - + +extern void do_cmd_quaff_potion(void); +extern void do_cmd_quaff_potion_aux(INVENTORY_IDX item); + diff --git a/src/cmd-read.c b/src/cmd-read.c index 5fa9e06df..6d65a713d 100644 --- a/src/cmd-read.c +++ b/src/cmd-read.c @@ -1,639 +1,639 @@ -/*! - * @file cmd-read.c - * @brief プレイヤーの読むコマンド実装 - * @date 2018/09/07 - * @details - * cmd6.cより分離。 - */ - -#include "angband.h" -#include "object-hook.h" -#include "artifact.h" -#include "avatar.h" -#include "player-status.h" -#include "rumor.h" -#include "realm-hex.h" - -#include "spells-object.h" -#include "spells-summon.h" -#include "spells-status.h" - -/*! - * @brief 巻物を読むコマンドのサブルーチン - * Read a scroll (from the pack or floor). - * @param item 読むオブジェクトの所持品ID - * @param known 判明済ならばTRUE - * @return なし - * @details - *
- * Certain scrolls can be "aborted" without losing the scroll.  These
- * include scrolls with no effects but recharge or identify, which are
- * cancelled before use.  XXX Reading them still takes a turn, though.
- * 
- */ -void do_cmd_read_scroll_aux(INVENTORY_IDX item, bool known) -{ - int k, used_up, ident, lev; - object_type *o_ptr; - - - /* Get the item (in the pack) */ - if (item >= 0) - { - o_ptr = &inventory[item]; - } - - /* Get the item (on the floor) */ - else - { - o_ptr = &o_list[0 - item]; - } - - take_turn(p_ptr, 100);; - if (cmd_limit_time_walk(p_ptr)) return; - - if (p_ptr->pclass == CLASS_BERSERKER) - { - msg_print(_("巻物なんて読めない。", "You cannot read.")); - return; - } - - if (music_singing_any()) stop_singing(); - - /* Hex */ - if (hex_spelling_any() && ((p_ptr->lev < 35) || hex_spell_fully())) stop_hex_spell_all(); - - /* Not identified yet */ - ident = FALSE; - - /* Object level */ - lev = k_info[o_ptr->k_idx].level; - - /* Assume the scroll will get used up */ - used_up = TRUE; - - if (o_ptr->tval == TV_SCROLL) - { - /* Analyze the scroll */ - switch (o_ptr->sval) - { - case SV_SCROLL_DARKNESS: - { - if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark)) - { - (void)set_blind(p_ptr->blind + 3 + randint1(5)); - } - if (unlite_area(10, 3)) ident = TRUE; - break; - } - - case SV_SCROLL_AGGRAVATE_MONSTER: - { - msg_print(_("カン高くうなる様な音が辺りを覆った。", "There is a high pitched humming noise.")); - aggravate_monsters(0); - ident = TRUE; - break; - } - - case SV_SCROLL_CURSE_ARMOR: - { - if (curse_armor()) ident = TRUE; - break; - } - - case SV_SCROLL_CURSE_WEAPON: - { - k = 0; - if (has_melee_weapon(INVEN_RARM)) - { - k = INVEN_RARM; - if (has_melee_weapon(INVEN_LARM) && one_in_(2)) k = INVEN_LARM; - } - else if (has_melee_weapon(INVEN_LARM)) k = INVEN_LARM; - if (k && curse_weapon(FALSE, k)) ident = TRUE; - break; - } - - case SV_SCROLL_SUMMON_MONSTER: - { - for (k = 0; k < randint1(3); k++) - { - if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) - { - ident = TRUE; - } - } - break; - } - - case SV_SCROLL_SUMMON_UNDEAD: - { - for (k = 0; k < randint1(3); k++) - { - if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, SUMMON_UNDEAD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) - { - ident = TRUE; - } - } - break; - } - - case SV_SCROLL_SUMMON_PET: - { - if (summon_specific(-1, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0')) - { - ident = TRUE; - } - break; - } - - case SV_SCROLL_SUMMON_KIN: - { - if (summon_kin_player(p_ptr->lev, p_ptr->y, p_ptr->x, (PM_FORCE_PET | PM_ALLOW_GROUP))) - { - ident = TRUE; - } - break; - } - - case SV_SCROLL_TRAP_CREATION: - { - if (trap_creation(p_ptr->y, p_ptr->x)) ident = TRUE; - break; - } - - case SV_SCROLL_PHASE_DOOR: - { - teleport_player(10, 0L); - ident = TRUE; - break; - } - - case SV_SCROLL_TELEPORT: - { - teleport_player(100, 0L); - ident = TRUE; - break; - } - - case SV_SCROLL_TELEPORT_LEVEL: - { - (void)teleport_level(0); - ident = TRUE; - break; - } - - case SV_SCROLL_WORD_OF_RECALL: - { - if (!recall_player(p_ptr, randint0(21) + 15)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_IDENTIFY: - { - if (!ident_spell(FALSE)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_STAR_IDENTIFY: - { - if (!identify_fully(FALSE)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_REMOVE_CURSE: - { - if (remove_curse()) - { - ident = TRUE; - } - break; - } - - case SV_SCROLL_STAR_REMOVE_CURSE: - { - if (remove_all_curse()) - { - ident = TRUE; - } - break; - } - - case SV_SCROLL_ENCHANT_ARMOR: - { - ident = TRUE; - if (!enchant_spell(0, 0, 1)) used_up = FALSE; - break; - } - - case SV_SCROLL_ENCHANT_WEAPON_TO_HIT: - { - if (!enchant_spell(1, 0, 0)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_ENCHANT_WEAPON_TO_DAM: - { - if (!enchant_spell(0, 1, 0)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_STAR_ENCHANT_ARMOR: - { - if (!enchant_spell(0, 0, randint1(3) + 2)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_STAR_ENCHANT_WEAPON: - { - if (!enchant_spell(randint1(3), randint1(3), 0)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_RECHARGING: - { - if (!recharge(130)) used_up = FALSE; - ident = TRUE; - break; - } - - case SV_SCROLL_MUNDANITY: - { - ident = TRUE; - if (!mundane_spell(FALSE)) used_up = FALSE; - break; - } - - case SV_SCROLL_LIGHT: - { - if (lite_area(damroll(2, 8), 2)) ident = TRUE; - break; - } - - case SV_SCROLL_MAPPING: - { - map_area(DETECT_RAD_MAP); - ident = TRUE; - break; - } - - case SV_SCROLL_DETECT_GOLD: - { - if (detect_treasure(DETECT_RAD_DEFAULT)) ident = TRUE; - if (detect_objects_gold(DETECT_RAD_DEFAULT)) ident = TRUE; - break; - } - - case SV_SCROLL_DETECT_ITEM: - { - if (detect_objects_normal(DETECT_RAD_DEFAULT)) ident = TRUE; - break; - } - - case SV_SCROLL_DETECT_TRAP: - { - if (detect_traps(DETECT_RAD_DEFAULT, known)) ident = TRUE; - break; - } - - case SV_SCROLL_DETECT_DOOR: - { - if (detect_doors(DETECT_RAD_DEFAULT)) ident = TRUE; - if (detect_stairs(DETECT_RAD_DEFAULT)) ident = TRUE; - break; - } - - case SV_SCROLL_DETECT_INVIS: - { - if (detect_monsters_invis(DETECT_RAD_DEFAULT)) ident = TRUE; - break; - } - - case SV_SCROLL_SATISFY_HUNGER: - { - if (set_food(PY_FOOD_MAX - 1)) ident = TRUE; - break; - } - - case SV_SCROLL_BLESSING: - { - if (set_blessed(p_ptr->blessed + randint1(12) + 6, FALSE)) ident = TRUE; - break; - } - - case SV_SCROLL_HOLY_CHANT: - { - if (set_blessed(p_ptr->blessed + randint1(24) + 12, FALSE)) ident = TRUE; - break; - } - - case SV_SCROLL_HOLY_PRAYER: - { - if (set_blessed(p_ptr->blessed + randint1(48) + 24, FALSE)) ident = TRUE; - break; - } - - case SV_SCROLL_MONSTER_CONFUSION: - { - if (!(p_ptr->special_attack & ATTACK_CONFUSE)) - { - msg_print(_("手が輝き始めた。", "Your hands begin to glow.")); - p_ptr->special_attack |= ATTACK_CONFUSE; - p_ptr->redraw |= (PR_STATUS); - ident = TRUE; - } - break; - } - - case SV_SCROLL_PROTECTION_FROM_EVIL: - { - k = 3 * p_ptr->lev; - if (set_protevil(p_ptr->protevil + randint1(25) + k, FALSE)) ident = TRUE; - break; - } - - case SV_SCROLL_RUNE_OF_PROTECTION: - { - warding_glyph(); - ident = TRUE; - break; - } - - case SV_SCROLL_TRAP_DOOR_DESTRUCTION: - { - if (destroy_doors_touch()) ident = TRUE; - break; - } - - case SV_SCROLL_STAR_DESTRUCTION: - { - if (destroy_area(p_ptr->y, p_ptr->x, 13 + randint0(5), FALSE)) - ident = TRUE; - else - msg_print(_("ダンジョンが揺れた...", "The dungeon trembles...")); - - break; - } - - case SV_SCROLL_DISPEL_UNDEAD: - { - if (dispel_undead(80)) ident = TRUE; - break; - } - - case SV_SCROLL_SPELL: - { - if ((p_ptr->pclass == CLASS_WARRIOR) || - (p_ptr->pclass == CLASS_IMITATOR) || - (p_ptr->pclass == CLASS_MINDCRAFTER) || - (p_ptr->pclass == CLASS_SORCERER) || - (p_ptr->pclass == CLASS_ARCHER) || - (p_ptr->pclass == CLASS_MAGIC_EATER) || - (p_ptr->pclass == CLASS_RED_MAGE) || - (p_ptr->pclass == CLASS_SAMURAI) || - (p_ptr->pclass == CLASS_BLUE_MAGE) || - (p_ptr->pclass == CLASS_CAVALRY) || - (p_ptr->pclass == CLASS_BERSERKER) || - (p_ptr->pclass == CLASS_SMITH) || - (p_ptr->pclass == CLASS_MIRROR_MASTER) || - (p_ptr->pclass == CLASS_NINJA) || - (p_ptr->pclass == CLASS_SNIPER)) break; - p_ptr->add_spells++; - p_ptr->update |= (PU_SPELLS); - ident = TRUE; - break; - } - - case SV_SCROLL_GENOCIDE: - { - (void)symbol_genocide(300, TRUE); - ident = TRUE; - break; - } - - case SV_SCROLL_MASS_GENOCIDE: - { - (void)mass_genocide(300, TRUE); - ident = TRUE; - break; - } - - case SV_SCROLL_ACQUIREMENT: - { - acquirement(p_ptr->y, p_ptr->x, 1, TRUE, FALSE, FALSE); - ident = TRUE; - break; - } - - case SV_SCROLL_STAR_ACQUIREMENT: - { - acquirement(p_ptr->y, p_ptr->x, randint1(2) + 1, TRUE, FALSE, FALSE); - ident = TRUE; - break; - } - - /* New Hengband scrolls */ - case SV_SCROLL_FIRE: - { - fire_ball(GF_FIRE, 0, 666, 4); - /* Note: "Double" damage since it is centered on the player ... */ - if (!(IS_OPPOSE_FIRE() || p_ptr->resist_fire || p_ptr->immune_fire)) - take_hit(DAMAGE_NOESCAPE, 50+randint1(50), _("炎の巻物", "a Scroll of Fire"), -1); - - ident = TRUE; - break; - } - - - case SV_SCROLL_ICE: - { - fire_ball(GF_ICE, 0, 777, 4); - if (!(IS_OPPOSE_COLD() || p_ptr->resist_cold || p_ptr->immune_cold)) - take_hit(DAMAGE_NOESCAPE, 100+randint1(100), _("氷の巻物", "a Scroll of Ice"), -1); - - ident = TRUE; - break; - } - - case SV_SCROLL_CHAOS: - { - fire_ball(GF_CHAOS, 0, 1000, 4); - if (!p_ptr->resist_chaos) - take_hit(DAMAGE_NOESCAPE, 111+randint1(111), _("ログルスの巻物", "a Scroll of Logrus"), -1); - - ident = TRUE; - break; - } - - case SV_SCROLL_RUMOR: - { - msg_print(_("巻物にはメッセージが書かれている:", "There is message on the scroll. It says:")); - msg_print(NULL); - display_rumor(TRUE); - msg_print(NULL); - msg_print(_("巻物は煙を立てて消え去った!", "The scroll disappears in a puff of smoke!")); - - ident = TRUE; - break; - } - - case SV_SCROLL_ARTIFACT: - { - ident = TRUE; - if (!artifact_scroll()) used_up = FALSE; - break; - } - - case SV_SCROLL_RESET_RECALL: - { - ident = TRUE; - if (!reset_recall()) used_up = FALSE; - break; - } - - case SV_SCROLL_AMUSEMENT: - { - ident = TRUE; - amusement(p_ptr->y, p_ptr->x, 1, FALSE); - break; - } - - case SV_SCROLL_STAR_AMUSEMENT: - { - ident = TRUE; - amusement(p_ptr->y, p_ptr->x, randint1(2) + 1, FALSE); - break; - } - } - } - else if (o_ptr->name1 == ART_GHB) - { - msg_print(_("私は苦労して『グレーター・ヘル=ビースト』を倒した。", "I had a very hard time to kill the Greater hell-beast, ")); - msg_print(_("しかし手に入ったのはこのきたないTシャツだけだった。", "but all I got was this lousy t-shirt!")); - used_up = FALSE; - } - else if (o_ptr->name1 == ART_POWER) - { - msg_print(_("「一つの指輪は全てを統べ、", "'One Ring to rule them all, ")); - msg_print(NULL); - msg_print(_("一つの指輪は全てを見つけ、", "One Ring to find them, ")); - msg_print(NULL); - msg_print(_("一つの指輪は全てを捕らえて", "One Ring to bring them all ")); - msg_print(NULL); - msg_print(_("暗闇の中に繋ぎとめる。」", "and in the darkness bind them.'")); - used_up = FALSE; - } - else if (o_ptr->tval==TV_PARCHMENT) - { - concptr q; - GAME_TEXT o_name[MAX_NLEN]; - char buf[1024]; - screen_save(); - - q=format("book-%d_jp.txt",o_ptr->sval); - - /* Display object description */ - object_desc(o_name, o_ptr, OD_NAME_ONLY); - - /* Build the filename */ - path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, q); - - /* Peruse the help file */ - (void)show_file(TRUE, buf, o_name, 0, 0); - screen_load(); - - used_up=FALSE; - } - - p_ptr->update |= (PU_COMBINE | PU_REORDER); - - if (!(object_is_aware(o_ptr))) - { - chg_virtue(V_PATIENCE, -1); - chg_virtue(V_CHANCE, 1); - chg_virtue(V_KNOWLEDGE, -1); - } - - /* The item was tried */ - object_tried(o_ptr); - - /* An identification was made */ - if (ident && !object_is_aware(o_ptr)) - { - object_aware(o_ptr); - gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); - } - - p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); - - - /* Hack -- allow certain scrolls to be "preserved" */ - if (!used_up) - { - return; - } - - sound(SOUND_SCROLL); - - /* Destroy a scroll in the pack */ - if (item >= 0) - { - inven_item_increase(item, -1); - inven_item_describe(item); - inven_item_optimize(item); - } - - /* Destroy a scroll on the floor */ - else - { - floor_item_increase(0 - item, -1); - floor_item_describe(0 - item); - floor_item_optimize(0 - item); - } -} - -/*! - * @brief 読むコマンドのメインルーチン / - * Eat some food (from the pack or floor) - * @return なし - */ -void do_cmd_read_scroll(void) -{ - object_type *o_ptr; - OBJECT_IDX item; - concptr q, s; - - if (p_ptr->wild_mode) - { - return; - } - - if (cmd_limit_arena(p_ptr)) return; - - if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) - { - set_action(ACTION_NONE); - } - - if (cmd_limit_blind(p_ptr)) return; - if (cmd_limit_confused(p_ptr)) return; - - /* Restrict choices to scrolls */ - item_tester_hook = item_tester_hook_readable; - - q = _("どの巻物を読みますか? ", "Read which scroll? "); - s = _("読める巻物がない。", "You have no scrolls to read."); - - o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); - if (!o_ptr) return; - - /* Read the scroll */ - do_cmd_read_scroll_aux(item, object_is_aware(o_ptr)); -} +/*! + * @file cmd-read.c + * @brief プレイヤーの読むコマンド実装 + * @date 2018/09/07 + * @details + * cmd6.cより分離。 + */ + +#include "angband.h" +#include "object-hook.h" +#include "artifact.h" +#include "avatar.h" +#include "player-status.h" +#include "rumor.h" +#include "realm-hex.h" + +#include "spells-object.h" +#include "spells-summon.h" +#include "spells-status.h" + +/*! + * @brief 巻物を読むコマンドのサブルーチン + * Read a scroll (from the pack or floor). + * @param item 読むオブジェクトの所持品ID + * @param known 判明済ならばTRUE + * @return なし + * @details + *
+ * Certain scrolls can be "aborted" without losing the scroll.  These
+ * include scrolls with no effects but recharge or identify, which are
+ * cancelled before use.  XXX Reading them still takes a turn, though.
+ * 
+ */ +void do_cmd_read_scroll_aux(INVENTORY_IDX item, bool known) +{ + int k, used_up, ident, lev; + object_type *o_ptr; + + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + take_turn(p_ptr, 100);; + if (cmd_limit_time_walk(p_ptr)) return; + + if (p_ptr->pclass == CLASS_BERSERKER) + { + msg_print(_("巻物なんて読めない。", "You cannot read.")); + return; + } + + if (music_singing_any()) stop_singing(); + + /* Hex */ + if (hex_spelling_any() && ((p_ptr->lev < 35) || hex_spell_fully())) stop_hex_spell_all(); + + /* Not identified yet */ + ident = FALSE; + + /* Object level */ + lev = k_info[o_ptr->k_idx].level; + + /* Assume the scroll will get used up */ + used_up = TRUE; + + if (o_ptr->tval == TV_SCROLL) + { + /* Analyze the scroll */ + switch (o_ptr->sval) + { + case SV_SCROLL_DARKNESS: + { + if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark)) + { + (void)set_blind(p_ptr->blind + 3 + randint1(5)); + } + if (unlite_area(10, 3)) ident = TRUE; + break; + } + + case SV_SCROLL_AGGRAVATE_MONSTER: + { + msg_print(_("カン高くうなる様な音が辺りを覆った。", "There is a high pitched humming noise.")); + aggravate_monsters(0); + ident = TRUE; + break; + } + + case SV_SCROLL_CURSE_ARMOR: + { + if (curse_armor()) ident = TRUE; + break; + } + + case SV_SCROLL_CURSE_WEAPON: + { + k = 0; + if (has_melee_weapon(INVEN_RARM)) + { + k = INVEN_RARM; + if (has_melee_weapon(INVEN_LARM) && one_in_(2)) k = INVEN_LARM; + } + else if (has_melee_weapon(INVEN_LARM)) k = INVEN_LARM; + if (k && curse_weapon(FALSE, k)) ident = TRUE; + break; + } + + case SV_SCROLL_SUMMON_MONSTER: + { + for (k = 0; k < randint1(3); k++) + { + if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) + { + ident = TRUE; + } + } + break; + } + + case SV_SCROLL_SUMMON_UNDEAD: + { + for (k = 0; k < randint1(3); k++) + { + if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, SUMMON_UNDEAD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) + { + ident = TRUE; + } + } + break; + } + + case SV_SCROLL_SUMMON_PET: + { + if (summon_specific(-1, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0')) + { + ident = TRUE; + } + break; + } + + case SV_SCROLL_SUMMON_KIN: + { + if (summon_kin_player(p_ptr->lev, p_ptr->y, p_ptr->x, (PM_FORCE_PET | PM_ALLOW_GROUP))) + { + ident = TRUE; + } + break; + } + + case SV_SCROLL_TRAP_CREATION: + { + if (trap_creation(p_ptr->y, p_ptr->x)) ident = TRUE; + break; + } + + case SV_SCROLL_PHASE_DOOR: + { + teleport_player(10, 0L); + ident = TRUE; + break; + } + + case SV_SCROLL_TELEPORT: + { + teleport_player(100, 0L); + ident = TRUE; + break; + } + + case SV_SCROLL_TELEPORT_LEVEL: + { + (void)teleport_level(0); + ident = TRUE; + break; + } + + case SV_SCROLL_WORD_OF_RECALL: + { + if (!recall_player(p_ptr, randint0(21) + 15)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_IDENTIFY: + { + if (!ident_spell(FALSE)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_STAR_IDENTIFY: + { + if (!identify_fully(FALSE)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_REMOVE_CURSE: + { + if (remove_curse()) + { + ident = TRUE; + } + break; + } + + case SV_SCROLL_STAR_REMOVE_CURSE: + { + if (remove_all_curse()) + { + ident = TRUE; + } + break; + } + + case SV_SCROLL_ENCHANT_ARMOR: + { + ident = TRUE; + if (!enchant_spell(0, 0, 1)) used_up = FALSE; + break; + } + + case SV_SCROLL_ENCHANT_WEAPON_TO_HIT: + { + if (!enchant_spell(1, 0, 0)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_ENCHANT_WEAPON_TO_DAM: + { + if (!enchant_spell(0, 1, 0)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_STAR_ENCHANT_ARMOR: + { + if (!enchant_spell(0, 0, randint1(3) + 2)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_STAR_ENCHANT_WEAPON: + { + if (!enchant_spell(randint1(3), randint1(3), 0)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_RECHARGING: + { + if (!recharge(130)) used_up = FALSE; + ident = TRUE; + break; + } + + case SV_SCROLL_MUNDANITY: + { + ident = TRUE; + if (!mundane_spell(FALSE)) used_up = FALSE; + break; + } + + case SV_SCROLL_LIGHT: + { + if (lite_area(damroll(2, 8), 2)) ident = TRUE; + break; + } + + case SV_SCROLL_MAPPING: + { + map_area(DETECT_RAD_MAP); + ident = TRUE; + break; + } + + case SV_SCROLL_DETECT_GOLD: + { + if (detect_treasure(DETECT_RAD_DEFAULT)) ident = TRUE; + if (detect_objects_gold(DETECT_RAD_DEFAULT)) ident = TRUE; + break; + } + + case SV_SCROLL_DETECT_ITEM: + { + if (detect_objects_normal(DETECT_RAD_DEFAULT)) ident = TRUE; + break; + } + + case SV_SCROLL_DETECT_TRAP: + { + if (detect_traps(DETECT_RAD_DEFAULT, known)) ident = TRUE; + break; + } + + case SV_SCROLL_DETECT_DOOR: + { + if (detect_doors(DETECT_RAD_DEFAULT)) ident = TRUE; + if (detect_stairs(DETECT_RAD_DEFAULT)) ident = TRUE; + break; + } + + case SV_SCROLL_DETECT_INVIS: + { + if (detect_monsters_invis(DETECT_RAD_DEFAULT)) ident = TRUE; + break; + } + + case SV_SCROLL_SATISFY_HUNGER: + { + if (set_food(PY_FOOD_MAX - 1)) ident = TRUE; + break; + } + + case SV_SCROLL_BLESSING: + { + if (set_blessed(p_ptr->blessed + randint1(12) + 6, FALSE)) ident = TRUE; + break; + } + + case SV_SCROLL_HOLY_CHANT: + { + if (set_blessed(p_ptr->blessed + randint1(24) + 12, FALSE)) ident = TRUE; + break; + } + + case SV_SCROLL_HOLY_PRAYER: + { + if (set_blessed(p_ptr->blessed + randint1(48) + 24, FALSE)) ident = TRUE; + break; + } + + case SV_SCROLL_MONSTER_CONFUSION: + { + if (!(p_ptr->special_attack & ATTACK_CONFUSE)) + { + msg_print(_("手が輝き始めた。", "Your hands begin to glow.")); + p_ptr->special_attack |= ATTACK_CONFUSE; + p_ptr->redraw |= (PR_STATUS); + ident = TRUE; + } + break; + } + + case SV_SCROLL_PROTECTION_FROM_EVIL: + { + k = 3 * p_ptr->lev; + if (set_protevil(p_ptr->protevil + randint1(25) + k, FALSE)) ident = TRUE; + break; + } + + case SV_SCROLL_RUNE_OF_PROTECTION: + { + warding_glyph(); + ident = TRUE; + break; + } + + case SV_SCROLL_TRAP_DOOR_DESTRUCTION: + { + if (destroy_doors_touch()) ident = TRUE; + break; + } + + case SV_SCROLL_STAR_DESTRUCTION: + { + if (destroy_area(p_ptr->y, p_ptr->x, 13 + randint0(5), FALSE)) + ident = TRUE; + else + msg_print(_("ダンジョンが揺れた...", "The dungeon trembles...")); + + break; + } + + case SV_SCROLL_DISPEL_UNDEAD: + { + if (dispel_undead(80)) ident = TRUE; + break; + } + + case SV_SCROLL_SPELL: + { + if ((p_ptr->pclass == CLASS_WARRIOR) || + (p_ptr->pclass == CLASS_IMITATOR) || + (p_ptr->pclass == CLASS_MINDCRAFTER) || + (p_ptr->pclass == CLASS_SORCERER) || + (p_ptr->pclass == CLASS_ARCHER) || + (p_ptr->pclass == CLASS_MAGIC_EATER) || + (p_ptr->pclass == CLASS_RED_MAGE) || + (p_ptr->pclass == CLASS_SAMURAI) || + (p_ptr->pclass == CLASS_BLUE_MAGE) || + (p_ptr->pclass == CLASS_CAVALRY) || + (p_ptr->pclass == CLASS_BERSERKER) || + (p_ptr->pclass == CLASS_SMITH) || + (p_ptr->pclass == CLASS_MIRROR_MASTER) || + (p_ptr->pclass == CLASS_NINJA) || + (p_ptr->pclass == CLASS_SNIPER)) break; + p_ptr->add_spells++; + p_ptr->update |= (PU_SPELLS); + ident = TRUE; + break; + } + + case SV_SCROLL_GENOCIDE: + { + (void)symbol_genocide(300, TRUE); + ident = TRUE; + break; + } + + case SV_SCROLL_MASS_GENOCIDE: + { + (void)mass_genocide(300, TRUE); + ident = TRUE; + break; + } + + case SV_SCROLL_ACQUIREMENT: + { + acquirement(p_ptr->y, p_ptr->x, 1, TRUE, FALSE, FALSE); + ident = TRUE; + break; + } + + case SV_SCROLL_STAR_ACQUIREMENT: + { + acquirement(p_ptr->y, p_ptr->x, randint1(2) + 1, TRUE, FALSE, FALSE); + ident = TRUE; + break; + } + + /* New Hengband scrolls */ + case SV_SCROLL_FIRE: + { + fire_ball(GF_FIRE, 0, 666, 4); + /* Note: "Double" damage since it is centered on the player ... */ + if (!(IS_OPPOSE_FIRE() || p_ptr->resist_fire || p_ptr->immune_fire)) + take_hit(DAMAGE_NOESCAPE, 50+randint1(50), _("炎の巻物", "a Scroll of Fire"), -1); + + ident = TRUE; + break; + } + + + case SV_SCROLL_ICE: + { + fire_ball(GF_ICE, 0, 777, 4); + if (!(IS_OPPOSE_COLD() || p_ptr->resist_cold || p_ptr->immune_cold)) + take_hit(DAMAGE_NOESCAPE, 100+randint1(100), _("氷の巻物", "a Scroll of Ice"), -1); + + ident = TRUE; + break; + } + + case SV_SCROLL_CHAOS: + { + fire_ball(GF_CHAOS, 0, 1000, 4); + if (!p_ptr->resist_chaos) + take_hit(DAMAGE_NOESCAPE, 111+randint1(111), _("ログルスの巻物", "a Scroll of Logrus"), -1); + + ident = TRUE; + break; + } + + case SV_SCROLL_RUMOR: + { + msg_print(_("巻物にはメッセージが書かれている:", "There is message on the scroll. It says:")); + msg_print(NULL); + display_rumor(TRUE); + msg_print(NULL); + msg_print(_("巻物は煙を立てて消え去った!", "The scroll disappears in a puff of smoke!")); + + ident = TRUE; + break; + } + + case SV_SCROLL_ARTIFACT: + { + ident = TRUE; + if (!artifact_scroll()) used_up = FALSE; + break; + } + + case SV_SCROLL_RESET_RECALL: + { + ident = TRUE; + if (!reset_recall()) used_up = FALSE; + break; + } + + case SV_SCROLL_AMUSEMENT: + { + ident = TRUE; + amusement(p_ptr->y, p_ptr->x, 1, FALSE); + break; + } + + case SV_SCROLL_STAR_AMUSEMENT: + { + ident = TRUE; + amusement(p_ptr->y, p_ptr->x, randint1(2) + 1, FALSE); + break; + } + } + } + else if (o_ptr->name1 == ART_GHB) + { + msg_print(_("私は苦労して『グレーター・ヘル=ビースト』を倒した。", "I had a very hard time to kill the Greater hell-beast, ")); + msg_print(_("しかし手に入ったのはこのきたないTシャツだけだった。", "but all I got was this lousy t-shirt!")); + used_up = FALSE; + } + else if (o_ptr->name1 == ART_POWER) + { + msg_print(_("「一つの指輪は全てを統べ、", "'One Ring to rule them all, ")); + msg_print(NULL); + msg_print(_("一つの指輪は全てを見つけ、", "One Ring to find them, ")); + msg_print(NULL); + msg_print(_("一つの指輪は全てを捕らえて", "One Ring to bring them all ")); + msg_print(NULL); + msg_print(_("暗闇の中に繋ぎとめる。」", "and in the darkness bind them.'")); + used_up = FALSE; + } + else if (o_ptr->tval==TV_PARCHMENT) + { + concptr q; + GAME_TEXT o_name[MAX_NLEN]; + char buf[1024]; + screen_save(); + + q=format("book-%d_jp.txt",o_ptr->sval); + + /* Display object description */ + object_desc(o_name, o_ptr, OD_NAME_ONLY); + + /* Build the filename */ + path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, q); + + /* Peruse the help file */ + (void)show_file(TRUE, buf, o_name, 0, 0); + screen_load(); + + used_up=FALSE; + } + + p_ptr->update |= (PU_COMBINE | PU_REORDER); + + if (!(object_is_aware(o_ptr))) + { + chg_virtue(V_PATIENCE, -1); + chg_virtue(V_CHANCE, 1); + chg_virtue(V_KNOWLEDGE, -1); + } + + /* The item was tried */ + object_tried(o_ptr); + + /* An identification was made */ + if (ident && !object_is_aware(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Hack -- allow certain scrolls to be "preserved" */ + if (!used_up) + { + return; + } + + sound(SOUND_SCROLL); + + /* Destroy a scroll in the pack */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Destroy a scroll on the floor */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } +} + +/*! + * @brief 読むコマンドのメインルーチン / + * Eat some food (from the pack or floor) + * @return なし + */ +void do_cmd_read_scroll(void) +{ + object_type *o_ptr; + OBJECT_IDX item; + concptr q, s; + + if (p_ptr->wild_mode) + { + return; + } + + if (cmd_limit_arena(p_ptr)) return; + + if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) + { + set_action(ACTION_NONE); + } + + if (cmd_limit_blind(p_ptr)) return; + if (cmd_limit_confused(p_ptr)) return; + + /* Restrict choices to scrolls */ + item_tester_hook = item_tester_hook_readable; + + q = _("どの巻物を読みますか? ", "Read which scroll? "); + s = _("読める巻物がない。", "You have no scrolls to read."); + + o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); + if (!o_ptr) return; + + /* Read the scroll */ + do_cmd_read_scroll_aux(item, object_is_aware(o_ptr)); +} diff --git a/src/cmd-read.h b/src/cmd-read.h index 305701ac3..9f4eae65c 100644 --- a/src/cmd-read.h +++ b/src/cmd-read.h @@ -1,4 +1,4 @@ - - -extern void do_cmd_read_scroll_aux(INVENTORY_IDX item, bool known); -extern void do_cmd_read_scroll(void); + + +extern void do_cmd_read_scroll_aux(INVENTORY_IDX item, bool known); +extern void do_cmd_read_scroll(void); diff --git a/src/cmd-spell.c b/src/cmd-spell.c index 767d4fdeb..a33923ec1 100644 --- a/src/cmd-spell.c +++ b/src/cmd-spell.c @@ -1,1395 +1,1395 @@ -/*! - @file cmd-spell.c - @brief 魔法のインターフェイスと発動 / Purpose: Do everything for each spell - @date 2013/12/31 - @author - 2013 Deskull rearranged comment for Doxygen. - */ - -#include "angband.h" -#include "selfinfo.h" -#include "spells-summon.h" -#include "realm-arcane.h" -#include "realm-chaos.h" -#include "realm-craft.h" -#include "realm-crusade.h" -#include "realm-daemon.h" -#include "realm-death.h" -#include "realm-hex.h" -#include "realm-hissatsu.h" -#include "realm-life.h" -#include "realm-nature.h" -#include "realm-song.h" -#include "realm-sorcery.h" -#include "realm-trump.h" -#include "angband.h" -#include "avatar.h" -#include "player-status.h" -#include "object-hook.h" - -/*! - * @brief - * 魔法の効果を「キャプション:ダイス+定数値」のフォーマットで出力する / Generate dice info string such as "foo 2d10" - * @param str キャプション - * @param dice ダイス数 - * @param sides ダイス目 - * @param base 固定値 - * @return フォーマットに従い整形された文字列 - */ -concptr info_string_dice(concptr str, DICE_NUMBER dice, DICE_SID sides, int base) -{ - /* Fix value */ - if (!dice) - return format("%s%d", str, base); - - /* Dice only */ - else if (!base) - return format("%s%dd%d", str, dice, sides); - - /* Dice plus base value */ - else - return format("%s%dd%d%+d", str, dice, sides, base); -} - - -/*! - * @brief 魔法によるダメージを出力する / Generate damage-dice info string such as "dam 2d10" - * @param dice ダイス数 - * @param sides ダイス目 - * @param base 固定値 - * @return フォーマットに従い整形された文字列 - */ -concptr info_damage(DICE_NUMBER dice, DICE_SID sides, int base) -{ - return info_string_dice(_("損傷:", "dam "), dice, sides, base); -} - -/*! - * @brief 魔法の効果時間を出力する / Generate duration info string such as "dur 20+1d20" - * @param base 固定値 - * @param sides ダイス目 - * @return フォーマットに従い整形された文字列 - */ -concptr info_duration(int base, DICE_SID sides) -{ - return format(_("期間:%d+1d%d", "dur %d+1d%d"), base, sides); -} - -/*! - * @brief 魔法の効果範囲を出力する / Generate range info string such as "range 5" - * @param range 効果範囲 - * @return フォーマットに従い整形された文字列 - */ -concptr info_range(POSITION range) -{ - return format(_("範囲:%d", "range %d"), range); -} - -/*! - * @brief 魔法による回復量を出力する / Generate heal info string such as "heal 2d8" - * @param dice ダイス数 - * @param sides ダイス目 - * @param base 固定値 - * @return フォーマットに従い整形された文字列 - */ -concptr info_heal(DICE_NUMBER dice, DICE_SID sides, int base) -{ - return info_string_dice(_("回復:", "heal "), dice, sides, base); -} - -/*! - * @brief 魔法効果発動までの遅延ターンを出力する / Generate delay info string such as "delay 15+1d15" - * @param base 固定値 - * @param sides ダイス目 - * @return フォーマットに従い整形された文字列 - */ -concptr info_delay(int base, DICE_SID sides) -{ - return format(_("遅延:%d+1d%d", "delay %d+1d%d"), base, sides); -} - - -/*! - * @brief 魔法によるダメージを出力する(固定値&複数回処理) / Generate multiple-damage info string such as "dam 25 each" - * @param dam 固定値 - * @return フォーマットに従い整形された文字列 - */ -concptr info_multi_damage(HIT_POINT dam) -{ - return format(_("損傷:各%d", "dam %d each"), dam); -} - - -/*! - * @brief 魔法によるダメージを出力する(ダイスのみ&複数回処理) / Generate multiple-damage-dice info string such as "dam 5d2 each" - * @param dice ダイス数 - * @param sides ダイス目 - * @return フォーマットに従い整形された文字列 - */ -concptr info_multi_damage_dice(DICE_NUMBER dice, DICE_SID sides) -{ - return format(_("損傷:各%dd%d", "dam %dd%d each"), dice, sides); -} - -/*! - * @brief 魔法による一般的な効力値を出力する(固定値) / Generate power info string such as "power 100" - * @param power 固定値 - * @return フォーマットに従い整形された文字列 - */ -concptr info_power(int power) -{ - return format(_("効力:%d", "power %d"), power); -} - - -/*! - * @brief 魔法による一般的な効力値を出力する(ダイス値) / Generate power info string such as "power 100" - * @param dice ダイス数 - * @param sides ダイス目 - * @return フォーマットに従い整形された文字列 - */ -/* - * Generate power info string such as "power 1d100" - */ -concptr info_power_dice(DICE_NUMBER dice, DICE_SID sides) -{ - return format(_("効力:%dd%d", "power %dd%d"), dice, sides); -} - - -/*! - * @brief 魔法の効果半径を出力する / Generate radius info string such as "rad 100" - * @param rad 効果半径 - * @return フォーマットに従い整形された文字列 - */ -concptr info_radius(POSITION rad) -{ - return format(_("半径:%d", "rad %d"), rad); -} - - -/*! - * @brief 魔法効果の限界重量を出力する / Generate weight info string such as "max wgt 15" - * @param weight 最大重量 - * @return フォーマットに従い整形された文字列 - */ -concptr info_weight(WEIGHT weight) -{ -#ifdef JP - return format("最大重量:%d.%dkg", lbtokg1(weight), lbtokg2(weight)); -#else - return format("max wgt %d", weight/10); -#endif -} - -/*! - * @brief 魔法処理のメインルーチン - * @param realm 魔法領域のID - * @param spell 各領域の魔法ID - * @param mode 求める処理 - * @return 各領域魔法に各種テキストを求めた場合は文字列参照ポインタ、そうでない場合はNULLポインタを返す。 - */ -concptr do_spell(REALM_IDX realm, SPELL_IDX spell, BIT_FLAGS mode) -{ - switch (realm) - { - case REALM_LIFE: return do_life_spell(spell, mode); - case REALM_SORCERY: return do_sorcery_spell(spell, mode); - case REALM_NATURE: return do_nature_spell(spell, mode); - case REALM_CHAOS: return do_chaos_spell(spell, mode); - case REALM_DEATH: return do_death_spell(spell, mode); - case REALM_TRUMP: return do_trump_spell(spell, mode); - case REALM_ARCANE: return do_arcane_spell(spell, mode); - case REALM_CRAFT: return do_craft_spell(spell, mode); - case REALM_DAEMON: return do_daemon_spell(spell, mode); - case REALM_CRUSADE: return do_crusade_spell(spell, mode); - case REALM_MUSIC: return do_music_spell(spell, mode); - case REALM_HISSATSU: return do_hissatsu_spell(spell, mode); - case REALM_HEX: return do_hex_spell(spell, mode); - } - - return NULL; -} - - -/*! - * @brief 領域魔法の閲覧、学習、使用選択するインターフェイス処理 - * Allow user to choose a spell/prayer from the given book. - * @param sn 選択した魔法IDを返す参照ポインタ - * @param prompt 魔法を利用する際の動詞表記 - * @param sval 魔道書のsval - * @param learned 閲覧/使用選択ならばTRUE、学習処理ならFALSE - * @param use_realm 魔法領域ID - * @return - *
- * If a valid spell is chosen, saves it in '*sn' and returns TRUE
- * If the user hits escape, returns FALSE, and set '*sn' to -1
- * If there are no legal choices, returns FALSE, and sets '*sn' to -2
- * The "prompt" should be "cast", "recite", or "study"
- * The "known" should be TRUE for cast/pray, FALSE for study
- * 
- */ -static int get_spell(SPELL_IDX *sn, concptr prompt, OBJECT_SUBTYPE_VALUE sval, bool learned, REALM_IDX use_realm) -{ - int i; - SPELL_IDX spell = -1; - int num = 0; - int ask = TRUE; - MANA_POINT need_mana; - SPELL_IDX spells[64]; - bool flag, redraw, okay; - char choice; - const magic_type *s_ptr; - char out_val[160]; - concptr p; - COMMAND_CODE code; -#ifdef JP - char jverb_buf[128]; -#endif - int menu_line = (use_menu ? 1 : 0); - - /* Get the spell, if available */ - if (repeat_pull(&code)) - { - *sn = (SPELL_IDX)code; - /* Verify the spell */ - if (spell_okay(*sn, learned, FALSE, use_realm)) - { - /* Success */ - return (TRUE); - } - } - - p = spell_category_name(mp_ptr->spell_book); - - /* Extract spells */ - for (spell = 0; spell < 32; spell++) - { - /* Check for this spell */ - if ((fake_spell_flags[sval] & (1L << spell))) - { - /* Collect this spell */ - spells[num++] = spell; - } - } - - /* Assume no usable spells */ - okay = FALSE; - - /* Assume no spells available */ - (*sn) = -2; - - /* Check for "okay" spells */ - for (i = 0; i < num; i++) - { - /* Look for "okay" spells */ - if (spell_okay(spells[i], learned, FALSE, use_realm)) okay = TRUE; - } - - /* No "okay" spells */ - if (!okay) return (FALSE); - if (((use_realm) != p_ptr->realm1) && ((use_realm) != p_ptr->realm2) && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) return FALSE; - if (((p_ptr->pclass == CLASS_SORCERER) || (p_ptr->pclass == CLASS_RED_MAGE)) && !is_magic(use_realm)) return FALSE; - if ((p_ptr->pclass == CLASS_RED_MAGE) && ((use_realm) != REALM_ARCANE) && (sval > 1)) return FALSE; - - /* Assume cancelled */ - *sn = (-1); - - /* Nothing chosen yet */ - flag = FALSE; - - /* No redraw yet */ - redraw = FALSE; - - p_ptr->window |= (PW_SPELL); - handle_stuff(); - - /* Build a prompt (accept all spells) */ -#ifdef JP - jverb(prompt, jverb_buf, JVERB_AND); - (void)strnfmt(out_val, 78, "(%^s:%c-%c, '*'で一覧, ESCで中断) どの%sを%^sますか? ", - p, I2A(0), I2A(num - 1), p, jverb_buf); -#else - (void)strnfmt(out_val, 78, "(%^ss %c-%c, *=List, ESC=exit) %^s which %s? ", - p, I2A(0), I2A(num - 1), prompt, p); -#endif - - /* Get a spell from the user */ - - choice = (always_show_list || use_menu) ? ESCAPE : 1; - while (!flag) - { - if (choice == ESCAPE) choice = ' '; - else if (!get_com(out_val, &choice, TRUE))break; - - if (use_menu && choice != ' ') - { - switch (choice) - { - case '0': - { - screen_load(); - return FALSE; - } - - case '8': - case 'k': - case 'K': - { - menu_line += (num - 1); - break; - } - - case '2': - case 'j': - case 'J': - { - menu_line++; - break; - } - - case 'x': - case 'X': - case '\r': - case '\n': - { - i = menu_line - 1; - ask = FALSE; - break; - } - } - if (menu_line > num) menu_line -= num; - /* Display a list of spells */ - print_spells(menu_line, spells, num, 1, 15, use_realm); - if (ask) continue; - } - else - { - /* Request redraw */ - if ((choice == ' ') || (choice == '*') || (choice == '?')) - { - /* Show the list */ - if (!redraw) - { - /* Show list */ - redraw = TRUE; - screen_save(); - - /* Display a list of spells */ - print_spells(menu_line, spells, num, 1, 15, use_realm); - } - - /* Hide the list */ - else - { - if (use_menu) continue; - - /* Hide list */ - redraw = FALSE; - screen_load(); - } - - /* Redo asking */ - continue; - } - - - /* Note verify */ - ask = (isupper(choice)); - - /* Lowercase */ - if (ask) choice = (char)tolower(choice); - - /* Extract request */ - i = (islower(choice) ? A2I(choice) : -1); - } - - /* Totally Illegal */ - if ((i < 0) || (i >= num)) - { - bell(); - continue; - } - - /* Save the spell index */ - spell = spells[i]; - - /* Require "okay" spells */ - if (!spell_okay(spell, learned, FALSE, use_realm)) - { - bell(); -#ifdef JP - msg_format("その%sを%sことはできません。", p, prompt); -#else - msg_format("You may not %s that %s.", prompt, p); -#endif - - continue; - } - - /* Verify it */ - if (ask) - { - char tmp_val[160]; - - /* Access the spell */ - if (!is_magic(use_realm)) - { - s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell]; - } - else - { - s_ptr = &mp_ptr->info[use_realm - 1][spell]; - } - - /* Extract mana consumption rate */ - if (use_realm == REALM_HISSATSU) - { - need_mana = s_ptr->smana; - } - else - { - need_mana = mod_need_mana(s_ptr->smana, spell, use_realm); - } - - /* Prompt */ -#ifdef JP - jverb(prompt, jverb_buf, JVERB_AND); - /* 英日切り替え機能に対応 */ - (void)strnfmt(tmp_val, 78, "%s(MP%d, 失敗率%d%%)を%sますか? ", - do_spell(use_realm, spell, SPELL_NAME), need_mana, - spell_chance(spell, use_realm), jverb_buf); -#else - (void)strnfmt(tmp_val, 78, "%^s %s (%d mana, %d%% fail)? ", - prompt, do_spell(use_realm, spell, SPELL_NAME), need_mana, - spell_chance(spell, use_realm)); -#endif - - - /* Belay that order */ - if (!get_check(tmp_val)) continue; - } - - /* Stop the loop */ - flag = TRUE; - } - - if (redraw) screen_load(); - - p_ptr->window |= (PW_SPELL); - handle_stuff(); - - /* Abort if needed */ - if (!flag) return FALSE; - - /* Save the choice */ - (*sn) = spell; - - repeat_push((COMMAND_CODE)spell); - - /* Success */ - return TRUE; -} - -/*! - * @brief プレイヤーの職業が練気術師の時、領域魔法と練気術を切り換える処理のインターフェイス - * @param browse_only 魔法と技能の閲覧を行うならばTRUE - * @return 魔道書を一冊も持っていないならTRUEを返す - */ -static void confirm_use_force(bool browse_only) -{ - char which; - COMMAND_CODE code; - - /* Get the item index */ - if (repeat_pull(&code) && (code == INVEN_FORCE)) - { - browse_only ? do_cmd_mind_browse() : do_cmd_mind(); - return; - } - - /* Show the prompt */ - prt(_("('w'練気術, ESC) 'w'かESCを押してください。 ", "(w for the Force, ESC) Hit 'w' or ESC. "), 0, 0); - - while (1) - { - /* Get a key */ - which = inkey(); - - if (which == ESCAPE) break; - else if (which == 'w') - { - repeat_push(INVEN_FORCE); - break; - } - } - - /* Clear the prompt line */ - prt("", 0, 0); - - if (which == 'w') - { - browse_only ? do_cmd_mind_browse() : do_cmd_mind(); - } -} - - -/*! - * @brief プレイヤーの魔法と技能を閲覧するコマンドのメインルーチン / - * Peruse the spells/prayers in a book - * @return なし - * @details - *
- * Note that *all* spells in the book are listed
- *
- * Note that browsing is allowed while confused or blind,
- * and in the dark, primarily to allow browsing in stores.
- * 
- */ -void do_cmd_browse(void) -{ - OBJECT_IDX item; - OBJECT_SUBTYPE_VALUE sval; - REALM_IDX use_realm = 0; - int j, line; - SPELL_IDX spell = -1; - int num = 0; - - SPELL_IDX spells[64]; - char temp[62 * 4]; - - object_type *o_ptr; - - concptr q, s; - - /* Warriors are illiterate */ - if (!(p_ptr->realm1 || p_ptr->realm2) && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) - { - msg_print(_("本を読むことができない!", "You cannot read books!")); - return; - } - - if (p_ptr->special_defense & KATA_MUSOU) - { - set_action(ACTION_NONE); - } - - if (p_ptr->pclass == CLASS_FORCETRAINER) - { - if (player_has_no_spellbooks()) - { - confirm_use_force(TRUE); - return; - } - } - - /* Restrict choices to "useful" books */ - if (p_ptr->realm2 == REALM_NONE) item_tester_tval = mp_ptr->spell_book; - else item_tester_hook = item_tester_learn_spell; - - q = _("どの本を読みますか? ", "Browse which book? "); - s = _("読める本がない。", "You have no books that you can read."); - - o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR | (p_ptr->pclass == CLASS_FORCETRAINER ? USE_FORCE : 0))); - if (!o_ptr) - { - if (item == INVEN_FORCE) /* the_force */ - { - do_cmd_mind_browse(); - return; - } - return; - } - - /* Access the item's sval */ - sval = o_ptr->sval; - - use_realm = tval2realm(o_ptr->tval); - - /* Track the object kind */ - object_kind_track(o_ptr->k_idx); - handle_stuff(); - - /* Extract spells */ - for (spell = 0; spell < 32; spell++) - { - /* Check for this spell */ - if ((fake_spell_flags[sval] & (1L << spell))) - { - /* Collect this spell */ - spells[num++] = spell; - } - } - - screen_save(); - prt("", 0, 0); - - /* Keep browsing spells. Exit browsing on cancel. */ - while (TRUE) - { - /* Ask for a spell, allow cancel */ - if (!get_spell(&spell, _("読む", "browse"), o_ptr->sval, TRUE, use_realm)) - { - /* If cancelled, leave immediately. */ - if (spell == -1) break; - - /* Display a list of spells */ - print_spells(0, spells, num, 1, 15, use_realm); - - /* Notify that there's nothing to see, and wait. */ - if (use_realm == REALM_HISSATSU) - prt(_("読める技がない。", "No techniques to browse."), 0, 0); - else - prt(_("読める呪文がない。", "No spells to browse."), 0, 0); - (void)inkey(); - - screen_load(); - - return; - } - - /* Clear lines, position cursor (really should use strlen here) */ - Term_erase(14, 14, 255); - Term_erase(14, 13, 255); - Term_erase(14, 12, 255); - Term_erase(14, 11, 255); - - roff_to_buf(do_spell(use_realm, spell, SPELL_DESC), 62, temp, sizeof(temp)); - - for (j = 0, line = 11; temp[j]; j += 1 + strlen(&temp[j])) - { - prt(&temp[j], line, 15); - line++; - } - } - screen_load(); -} - -/*! - * @brief プレイヤーの第二魔法領域を変更する / - * @param next_realm 変更先の魔法領域ID - * @return なし - */ -static void change_realm2(CHARACTER_IDX next_realm) -{ - int i, j = 0; - char tmp[80]; - - for (i = 0; i < 64; i++) - { - p_ptr->spell_order[j] = p_ptr->spell_order[i]; - if (p_ptr->spell_order[i] < 32) j++; - } - for (; j < 64; j++) - p_ptr->spell_order[j] = 99; - - for (i = 32; i < 64; i++) - { - p_ptr->spell_exp[i] = SPELL_EXP_UNSKILLED; - } - p_ptr->spell_learned2 = 0L; - p_ptr->spell_worked2 = 0L; - p_ptr->spell_forgotten2 = 0L; - - sprintf(tmp, _("魔法の領域を%sから%sに変更した。", "change magic realm from %s to %s."), realm_names[p_ptr->realm2], realm_names[next_realm]); - do_cmd_write_nikki(NIKKI_BUNSHOU, 0, tmp); - p_ptr->old_realm |= 1 << (p_ptr->realm2 - 1); - p_ptr->realm2 = next_realm; - - p_ptr->update |= (PU_REORDER); - p_ptr->update |= (PU_SPELLS); - handle_stuff(); - - /* Load an autopick preference file */ - autopick_load_pref(FALSE); -} - - -/*! - * @brief 魔法を学習するコマンドのメインルーチン / - * Study a book to gain a new spell/prayer - * @return なし - */ -void do_cmd_study(void) -{ - int i; - OBJECT_IDX item; - OBJECT_SUBTYPE_VALUE sval; - int increment = 0; - bool learned = FALSE; - - /* Spells of realm2 will have an increment of +32 */ - SPELL_IDX spell = -1; - - concptr p = spell_category_name(mp_ptr->spell_book); - - object_type *o_ptr; - - concptr q, s; - - if (!p_ptr->realm1) - { - msg_print(_("本を読むことができない!", "You cannot read books!")); - return; - } - - if (p_ptr->blind || no_lite()) - { - msg_print(_("目が見えない!", "You cannot see!")); - return; - } - - if (cmd_limit_confused(p_ptr)) return; - - if (!(p_ptr->new_spells)) - { - msg_format(_("新しい%sを覚えることはできない!", "You cannot learn any new %ss!"), p); - return; - } - - if (p_ptr->special_defense & KATA_MUSOU) - { - set_action(ACTION_NONE); - } - -#ifdef JP - if (p_ptr->new_spells < 10) { - msg_format("あと %d つの%sを学べる。", p_ptr->new_spells, p); - } - else { - msg_format("あと %d 個の%sを学べる。", p_ptr->new_spells, p); - } -#else - msg_format("You can learn %d new %s%s.", p_ptr->new_spells, p, - (p_ptr->new_spells == 1 ? "" : "s")); -#endif - - msg_print(NULL); - - - /* Restrict choices to "useful" books */ - if (p_ptr->realm2 == REALM_NONE) item_tester_tval = mp_ptr->spell_book; - else item_tester_hook = item_tester_learn_spell; - - q = _("どの本から学びますか? ", "Study which book? "); - s = _("読める本がない。", "You have no books that you can read."); - - o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); - if (!o_ptr) return; - - /* Access the item's sval */ - sval = o_ptr->sval; - - if (o_ptr->tval == REALM2_BOOK) increment = 32; - else if (o_ptr->tval != REALM1_BOOK) - { - if (!get_check(_("本当に魔法の領域を変更しますか?", "Really, change magic realm? "))) return; - change_realm2(tval2realm(o_ptr->tval)); - increment = 32; - } - - /* Track the object kind */ - object_kind_track(o_ptr->k_idx); - handle_stuff(); - - /* Mage -- Learn a selected spell */ - if (mp_ptr->spell_book != TV_LIFE_BOOK) - { - /* Ask for a spell, allow cancel */ - if (!get_spell(&spell, _("学ぶ", "study"), sval, FALSE, o_ptr->tval - TV_LIFE_BOOK + 1) && (spell == -1)) return; - } - - /* Priest -- Learn a random prayer */ - else - { - int k = 0; - int gift = -1; - - /* Extract spells */ - for (spell = 0; spell < 32; spell++) - { - /* Check spells in the book */ - if ((fake_spell_flags[sval] & (1L << spell))) - { - /* Skip non "okay" prayers */ - if (!spell_okay(spell, FALSE, TRUE, - (increment ? p_ptr->realm2 : p_ptr->realm1))) continue; - - /* Hack -- Prepare the randomizer */ - k++; - - /* Hack -- Apply the randomizer */ - if (one_in_(k)) gift = spell; - } - } - - /* Accept gift */ - spell = gift; - } - - /* Nothing to study */ - if (spell < 0) - { - msg_format(_("その本には学ぶべき%sがない。", "You cannot learn any %ss in that book."), p); - - /* Abort */ - return; - } - - if (increment) spell += increment; - - /* Learn the spell */ - if (spell < 32) - { - if (p_ptr->spell_learned1 & (1L << spell)) learned = TRUE; - else p_ptr->spell_learned1 |= (1L << spell); - } - else - { - if (p_ptr->spell_learned2 & (1L << (spell - 32))) learned = TRUE; - else p_ptr->spell_learned2 |= (1L << (spell - 32)); - } - - if (learned) - { - int max_exp = (spell < 32) ? SPELL_EXP_MASTER : SPELL_EXP_EXPERT; - int old_exp = p_ptr->spell_exp[spell]; - int new_rank = EXP_LEVEL_UNSKILLED; - concptr name = do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME); - - if (old_exp >= max_exp) - { - msg_format(_("その%sは完全に使いこなせるので学ぶ必要はない。", "You don't need to study this %s anymore."), p); - return; - } -#ifdef JP - if (!get_check(format("%sの%sをさらに学びます。よろしいですか?", name, p))) -#else - if (!get_check(format("You will study a %s of %s again. Are you sure? ", p, name))) -#endif - { - return; - } - else if (old_exp >= SPELL_EXP_EXPERT) - { - p_ptr->spell_exp[spell] = SPELL_EXP_MASTER; - new_rank = EXP_LEVEL_MASTER; - } - else if (old_exp >= SPELL_EXP_SKILLED) - { - if (spell >= 32) p_ptr->spell_exp[spell] = SPELL_EXP_EXPERT; - else p_ptr->spell_exp[spell] += SPELL_EXP_EXPERT - SPELL_EXP_SKILLED; - new_rank = EXP_LEVEL_EXPERT; - } - else if (old_exp >= SPELL_EXP_BEGINNER) - { - p_ptr->spell_exp[spell] = SPELL_EXP_SKILLED + (old_exp - SPELL_EXP_BEGINNER) * 2 / 3; - new_rank = EXP_LEVEL_SKILLED; - } - else - { - p_ptr->spell_exp[spell] = SPELL_EXP_BEGINNER + old_exp / 3; - new_rank = EXP_LEVEL_BEGINNER; - } - msg_format(_("%sの熟練度が%sに上がった。", "Your proficiency of %s is now %s rank."), name, exp_level_str[new_rank]); - } - else - { - /* Find the next open entry in "p_ptr->spell_order[]" */ - for (i = 0; i < 64; i++) - { - /* Stop at the first empty space */ - if (p_ptr->spell_order[i] == 99) break; - } - - /* Add the spell to the known list */ - p_ptr->spell_order[i++] = spell; - - /* Mention the result */ -#ifdef JP - /* 英日切り替え機能に対応 */ - if (mp_ptr->spell_book == TV_MUSIC_BOOK) - { - msg_format("%sを学んだ。", - do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME)); - } - else - { - msg_format("%sの%sを学んだ。", - do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME), p); - } -#else - msg_format("You have learned the %s of %s.", - p, do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME)); -#endif - } - - take_turn(p_ptr, 100);; - - switch (mp_ptr->spell_book) - { - case TV_LIFE_BOOK: - chg_virtue(V_FAITH, 1); - break; - case TV_DEATH_BOOK: - chg_virtue(V_UNLIFE, 1); - break; - case TV_NATURE_BOOK: - chg_virtue(V_NATURE, 1); - break; - default: - chg_virtue(V_KNOWLEDGE, 1); - break; - } - - sound(SOUND_STUDY); - - /* One less spell available */ - p_ptr->learned_spells++; - - /* Update Study */ - p_ptr->update |= (PU_SPELLS); - update_creature(p_ptr); - - /* Redraw object recall */ - p_ptr->window |= (PW_OBJECT); -} - - -/*! - * @brief 魔法を詠唱するコマンドのメインルーチン / - * Cast a spell - * @return なし - */ -void do_cmd_cast(void) -{ - OBJECT_IDX item; - OBJECT_SUBTYPE_VALUE sval; - SPELL_IDX spell; - REALM_IDX realm; - int chance; - int increment = 0; - REALM_IDX use_realm; - MANA_POINT need_mana; - - concptr prayer; - object_type *o_ptr; - const magic_type *s_ptr; - concptr q, s; - - bool over_exerted = FALSE; - - /* Require spell ability */ - if (!p_ptr->realm1 && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) - { - msg_print(_("呪文を唱えられない!", "You cannot cast spells!")); - return; - } - - /* Require lite */ - if (p_ptr->blind || no_lite()) - { - if (p_ptr->pclass == CLASS_FORCETRAINER) confirm_use_force(FALSE); - else - { - msg_print(_("目が見えない!", "You cannot see!")); - flush(); - } - return; - } - - if (cmd_limit_confused(p_ptr)) return; - - /* Hex */ - if (p_ptr->realm1 == REALM_HEX) - { - if (hex_spell_fully()) - { - bool flag = FALSE; - msg_print(_("これ以上新しい呪文を詠唱することはできない。", "Can not spell new spells more.")); - flush(); - if (p_ptr->lev >= 35) flag = stop_hex_spell(); - if (!flag) return; - } - } - - if (p_ptr->pclass == CLASS_FORCETRAINER) - { - if (player_has_no_spellbooks()) - { - confirm_use_force(FALSE); - return; - } - } - - prayer = spell_category_name(mp_ptr->spell_book); - - /* Restrict choices to spell books */ - item_tester_tval = mp_ptr->spell_book; - - q = _("どの呪文書を使いますか? ", "Use which book? "); - s = _("呪文書がない!", "You have no spell books!"); - - o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR | (p_ptr->pclass == CLASS_FORCETRAINER ? USE_FORCE : 0))); - if (!o_ptr) - { - if (item == INVEN_FORCE) /* the_force */ - { - do_cmd_mind(); - return; - } - return; - } - - /* Access the item's sval */ - sval = o_ptr->sval; - - if ((p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE) && (o_ptr->tval == REALM2_BOOK)) increment = 32; - - /* Track the object kind */ - object_kind_track(o_ptr->k_idx); - handle_stuff(); - - if ((p_ptr->pclass == CLASS_SORCERER) || (p_ptr->pclass == CLASS_RED_MAGE)) - realm = o_ptr->tval - TV_LIFE_BOOK + 1; - else if (increment) realm = p_ptr->realm2; - else realm = p_ptr->realm1; - - /* Ask for a spell */ -#ifdef JP - if (!get_spell(&spell, ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "詠唱する" : (mp_ptr->spell_book == TV_MUSIC_BOOK) ? "歌う" : "唱える"), - sval, TRUE, realm)) - { - if (spell == -2) msg_format("その本には知っている%sがない。", prayer); - return; - } -#else - if (!get_spell(&spell, ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "recite" : "cast"), - sval, TRUE, realm)) - { - if (spell == -2) - msg_format("You don't know any %ss in that book.", prayer); - return; - } -#endif - - - use_realm = tval2realm(o_ptr->tval); - - /* Hex */ - if (use_realm == REALM_HEX) - { - if (hex_spelling(spell)) - { - msg_print(_("その呪文はすでに詠唱中だ。", "You are already casting it.")); - return; - } - } - - if (!is_magic(use_realm)) - { - s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell]; - } - else - { - s_ptr = &mp_ptr->info[realm - 1][spell]; - } - - /* Extract mana consumption rate */ - need_mana = mod_need_mana(s_ptr->smana, spell, realm); - - /* Verify "dangerous" spells */ - if (need_mana > p_ptr->csp) - { - if (flush_failure) flush(); - - /* Warning */ -#ifdef JP - msg_format("その%sを%sのに十分なマジックポイントがない。", prayer, - ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "詠唱する" : (mp_ptr->spell_book == TV_LIFE_BOOK) ? "歌う" : "唱える")); -#else - msg_format("You do not have enough mana to %s this %s.", - ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "recite" : "cast"), - prayer); -#endif - - - if (!over_exert) return; - - /* Verify */ - if (!get_check_strict(_("それでも挑戦しますか? ", "Attempt it anyway? "), CHECK_OKAY_CANCEL)) return; - } - - /* Spell failure chance */ - chance = spell_chance(spell, use_realm); - - /* Sufficient mana */ - if (need_mana <= p_ptr->csp) - { - /* Use some mana */ - p_ptr->csp -= need_mana; - } - else over_exerted = TRUE; - p_ptr->redraw |= (PR_MANA); - - /* Failed spell */ - if (randint0(100) < chance) - { - if (flush_failure) flush(); - - msg_format(_("%sをうまく唱えられなかった!", "You failed to get the %s off!"), prayer); - sound(SOUND_FAIL); - - switch (realm) - { - case REALM_LIFE: - if (randint1(100) < chance) chg_virtue(V_VITALITY, -1); - break; - case REALM_DEATH: - if (randint1(100) < chance) chg_virtue(V_UNLIFE, -1); - break; - case REALM_NATURE: - if (randint1(100) < chance) chg_virtue(V_NATURE, -1); - break; - case REALM_DAEMON: - if (randint1(100) < chance) chg_virtue(V_JUSTICE, 1); - break; - case REALM_CRUSADE: - if (randint1(100) < chance) chg_virtue(V_JUSTICE, -1); - break; - case REALM_HEX: - if (randint1(100) < chance) chg_virtue(V_COMPASSION, -1); - break; - default: - if (randint1(100) < chance) chg_virtue(V_KNOWLEDGE, -1); - break; - } - - /* Failure casting may activate some side effect */ - do_spell(realm, spell, SPELL_FAIL); - - - if ((o_ptr->tval == TV_CHAOS_BOOK) && (randint1(100) < spell)) - { - msg_print(_("カオス的な効果を発生した!", "You produce a chaotic effect!")); - wild_magic(spell); - } - else if ((o_ptr->tval == TV_DEATH_BOOK) && (randint1(100) < spell)) - { - if ((sval == 3) && one_in_(2)) - { - sanity_blast(0, TRUE); - } - else - { - msg_print(_("痛い!", "It hurts!")); - take_hit(DAMAGE_LOSELIFE, damroll(o_ptr->sval + 1, 6), _("暗黒魔法の逆流", "a miscast Death spell"), -1); - - if ((spell > 15) && one_in_(6) && !p_ptr->hold_exp) - lose_exp(spell * 250); - } - } - else if ((o_ptr->tval == TV_MUSIC_BOOK) && (randint1(200) < spell)) - { - msg_print(_("いやな音が響いた", "An infernal sound echoed.")); - aggravate_monsters(0); - } - if (randint1(100) >= chance) - chg_virtue(V_CHANCE, -1); - } - - /* Process spell */ - else - { - /* Canceled spells cost neither a turn nor mana */ - if (!do_spell(realm, spell, SPELL_CAST)) return; - - if (randint1(100) < chance) - chg_virtue(V_CHANCE, 1); - - /* A spell was cast */ - if (!(increment ? - (p_ptr->spell_worked2 & (1L << spell)) : - (p_ptr->spell_worked1 & (1L << spell))) - && (p_ptr->pclass != CLASS_SORCERER) - && (p_ptr->pclass != CLASS_RED_MAGE)) - { - int e = s_ptr->sexp; - - /* The spell worked */ - if (realm == p_ptr->realm1) - { - p_ptr->spell_worked1 |= (1L << spell); - } - else - { - p_ptr->spell_worked2 |= (1L << spell); - } - - /* Gain experience */ - gain_exp(e * s_ptr->slevel); - - /* Redraw object recall */ - p_ptr->window |= (PW_OBJECT); - - switch (realm) - { - case REALM_LIFE: - chg_virtue(V_TEMPERANCE, 1); - chg_virtue(V_COMPASSION, 1); - chg_virtue(V_VITALITY, 1); - chg_virtue(V_DILIGENCE, 1); - break; - case REALM_DEATH: - chg_virtue(V_UNLIFE, 1); - chg_virtue(V_JUSTICE, -1); - chg_virtue(V_FAITH, -1); - chg_virtue(V_VITALITY, -1); - break; - case REALM_DAEMON: - chg_virtue(V_JUSTICE, -1); - chg_virtue(V_FAITH, -1); - chg_virtue(V_HONOUR, -1); - chg_virtue(V_TEMPERANCE, -1); - break; - case REALM_CRUSADE: - chg_virtue(V_FAITH, 1); - chg_virtue(V_JUSTICE, 1); - chg_virtue(V_SACRIFICE, 1); - chg_virtue(V_HONOUR, 1); - break; - case REALM_NATURE: - chg_virtue(V_NATURE, 1); - chg_virtue(V_HARMONY, 1); - break; - case REALM_HEX: - chg_virtue(V_JUSTICE, -1); - chg_virtue(V_FAITH, -1); - chg_virtue(V_HONOUR, -1); - chg_virtue(V_COMPASSION, -1); - break; - default: - chg_virtue(V_KNOWLEDGE, 1); - break; - } - } - switch (realm) - { - case REALM_LIFE: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_TEMPERANCE, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_COMPASSION, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_VITALITY, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_DILIGENCE, 1); - break; - case REALM_DEATH: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_UNLIFE, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_VITALITY, -1); - break; - case REALM_DAEMON: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_TEMPERANCE, -1); - break; - case REALM_CRUSADE: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_SACRIFICE, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, 1); - break; - case REALM_NATURE: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_NATURE, 1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HARMONY, 1); - break; - case REALM_HEX: - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, -1); - if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_COMPASSION, -1); - break; - } - if (mp_ptr->spell_xtra & MAGIC_GAIN_EXP) - { - s16b cur_exp = p_ptr->spell_exp[(increment ? 32 : 0) + spell]; - s16b exp_gain = 0; - - if (cur_exp < SPELL_EXP_BEGINNER) - exp_gain += 60; - else if (cur_exp < SPELL_EXP_SKILLED) - { - if ((dun_level > 4) && ((dun_level + 10) > p_ptr->lev)) - exp_gain = 8; - } - else if (cur_exp < SPELL_EXP_EXPERT) - { - if (((dun_level + 5) > p_ptr->lev) && ((dun_level + 5) > s_ptr->slevel)) - exp_gain = 2; - } - else if ((cur_exp < SPELL_EXP_MASTER) && !increment) - { - if (((dun_level + 5) > p_ptr->lev) && (dun_level > s_ptr->slevel)) - exp_gain = 1; - } - p_ptr->spell_exp[(increment ? 32 : 0) + spell] += exp_gain; - } - } - - take_turn(p_ptr, 100);; - - - /* Over-exert the player */ - if (over_exerted) - { - int oops = need_mana; - - /* No mana left */ - p_ptr->csp = 0; - p_ptr->csp_frac = 0; - - msg_print(_("精神を集中しすぎて気を失ってしまった!", "You faint from the effort!")); - - /* Hack -- Bypass free action */ - (void)set_paralyzed(p_ptr->paralyzed + randint1(5 * oops + 1)); - - switch (realm) - { - case REALM_LIFE: - chg_virtue(V_VITALITY, -10); - break; - case REALM_DEATH: - chg_virtue(V_UNLIFE, -10); - break; - case REALM_DAEMON: - chg_virtue(V_JUSTICE, 10); - break; - case REALM_NATURE: - chg_virtue(V_NATURE, -10); - break; - case REALM_CRUSADE: - chg_virtue(V_JUSTICE, -10); - break; - case REALM_HEX: - chg_virtue(V_COMPASSION, 10); - break; - default: - chg_virtue(V_KNOWLEDGE, -10); - break; - } - - /* Damage CON (possibly permanently) */ - if (randint0(100) < 50) - { - bool perm = (randint0(100) < 25); - - msg_print(_("体を悪くしてしまった!", "You have damaged your health!")); - - /* Reduce constitution */ - (void)dec_stat(A_CON, 15 + randint1(10), perm); - } - } - - p_ptr->window |= (PW_PLAYER); - p_ptr->window |= (PW_SPELL); -} +/*! + @file cmd-spell.c + @brief 魔法のインターフェイスと発動 / Purpose: Do everything for each spell + @date 2013/12/31 + @author + 2013 Deskull rearranged comment for Doxygen. + */ + +#include "angband.h" +#include "selfinfo.h" +#include "spells-summon.h" +#include "realm-arcane.h" +#include "realm-chaos.h" +#include "realm-craft.h" +#include "realm-crusade.h" +#include "realm-daemon.h" +#include "realm-death.h" +#include "realm-hex.h" +#include "realm-hissatsu.h" +#include "realm-life.h" +#include "realm-nature.h" +#include "realm-song.h" +#include "realm-sorcery.h" +#include "realm-trump.h" +#include "angband.h" +#include "avatar.h" +#include "player-status.h" +#include "object-hook.h" + +/*! + * @brief + * 魔法の効果を「キャプション:ダイス+定数値」のフォーマットで出力する / Generate dice info string such as "foo 2d10" + * @param str キャプション + * @param dice ダイス数 + * @param sides ダイス目 + * @param base 固定値 + * @return フォーマットに従い整形された文字列 + */ +concptr info_string_dice(concptr str, DICE_NUMBER dice, DICE_SID sides, int base) +{ + /* Fix value */ + if (!dice) + return format("%s%d", str, base); + + /* Dice only */ + else if (!base) + return format("%s%dd%d", str, dice, sides); + + /* Dice plus base value */ + else + return format("%s%dd%d%+d", str, dice, sides, base); +} + + +/*! + * @brief 魔法によるダメージを出力する / Generate damage-dice info string such as "dam 2d10" + * @param dice ダイス数 + * @param sides ダイス目 + * @param base 固定値 + * @return フォーマットに従い整形された文字列 + */ +concptr info_damage(DICE_NUMBER dice, DICE_SID sides, int base) +{ + return info_string_dice(_("損傷:", "dam "), dice, sides, base); +} + +/*! + * @brief 魔法の効果時間を出力する / Generate duration info string such as "dur 20+1d20" + * @param base 固定値 + * @param sides ダイス目 + * @return フォーマットに従い整形された文字列 + */ +concptr info_duration(int base, DICE_SID sides) +{ + return format(_("期間:%d+1d%d", "dur %d+1d%d"), base, sides); +} + +/*! + * @brief 魔法の効果範囲を出力する / Generate range info string such as "range 5" + * @param range 効果範囲 + * @return フォーマットに従い整形された文字列 + */ +concptr info_range(POSITION range) +{ + return format(_("範囲:%d", "range %d"), range); +} + +/*! + * @brief 魔法による回復量を出力する / Generate heal info string such as "heal 2d8" + * @param dice ダイス数 + * @param sides ダイス目 + * @param base 固定値 + * @return フォーマットに従い整形された文字列 + */ +concptr info_heal(DICE_NUMBER dice, DICE_SID sides, int base) +{ + return info_string_dice(_("回復:", "heal "), dice, sides, base); +} + +/*! + * @brief 魔法効果発動までの遅延ターンを出力する / Generate delay info string such as "delay 15+1d15" + * @param base 固定値 + * @param sides ダイス目 + * @return フォーマットに従い整形された文字列 + */ +concptr info_delay(int base, DICE_SID sides) +{ + return format(_("遅延:%d+1d%d", "delay %d+1d%d"), base, sides); +} + + +/*! + * @brief 魔法によるダメージを出力する(固定値&複数回処理) / Generate multiple-damage info string such as "dam 25 each" + * @param dam 固定値 + * @return フォーマットに従い整形された文字列 + */ +concptr info_multi_damage(HIT_POINT dam) +{ + return format(_("損傷:各%d", "dam %d each"), dam); +} + + +/*! + * @brief 魔法によるダメージを出力する(ダイスのみ&複数回処理) / Generate multiple-damage-dice info string such as "dam 5d2 each" + * @param dice ダイス数 + * @param sides ダイス目 + * @return フォーマットに従い整形された文字列 + */ +concptr info_multi_damage_dice(DICE_NUMBER dice, DICE_SID sides) +{ + return format(_("損傷:各%dd%d", "dam %dd%d each"), dice, sides); +} + +/*! + * @brief 魔法による一般的な効力値を出力する(固定値) / Generate power info string such as "power 100" + * @param power 固定値 + * @return フォーマットに従い整形された文字列 + */ +concptr info_power(int power) +{ + return format(_("効力:%d", "power %d"), power); +} + + +/*! + * @brief 魔法による一般的な効力値を出力する(ダイス値) / Generate power info string such as "power 100" + * @param dice ダイス数 + * @param sides ダイス目 + * @return フォーマットに従い整形された文字列 + */ +/* + * Generate power info string such as "power 1d100" + */ +concptr info_power_dice(DICE_NUMBER dice, DICE_SID sides) +{ + return format(_("効力:%dd%d", "power %dd%d"), dice, sides); +} + + +/*! + * @brief 魔法の効果半径を出力する / Generate radius info string such as "rad 100" + * @param rad 効果半径 + * @return フォーマットに従い整形された文字列 + */ +concptr info_radius(POSITION rad) +{ + return format(_("半径:%d", "rad %d"), rad); +} + + +/*! + * @brief 魔法効果の限界重量を出力する / Generate weight info string such as "max wgt 15" + * @param weight 最大重量 + * @return フォーマットに従い整形された文字列 + */ +concptr info_weight(WEIGHT weight) +{ +#ifdef JP + return format("最大重量:%d.%dkg", lbtokg1(weight), lbtokg2(weight)); +#else + return format("max wgt %d", weight/10); +#endif +} + +/*! + * @brief 魔法処理のメインルーチン + * @param realm 魔法領域のID + * @param spell 各領域の魔法ID + * @param mode 求める処理 + * @return 各領域魔法に各種テキストを求めた場合は文字列参照ポインタ、そうでない場合はNULLポインタを返す。 + */ +concptr do_spell(REALM_IDX realm, SPELL_IDX spell, BIT_FLAGS mode) +{ + switch (realm) + { + case REALM_LIFE: return do_life_spell(spell, mode); + case REALM_SORCERY: return do_sorcery_spell(spell, mode); + case REALM_NATURE: return do_nature_spell(spell, mode); + case REALM_CHAOS: return do_chaos_spell(spell, mode); + case REALM_DEATH: return do_death_spell(spell, mode); + case REALM_TRUMP: return do_trump_spell(spell, mode); + case REALM_ARCANE: return do_arcane_spell(spell, mode); + case REALM_CRAFT: return do_craft_spell(spell, mode); + case REALM_DAEMON: return do_daemon_spell(spell, mode); + case REALM_CRUSADE: return do_crusade_spell(spell, mode); + case REALM_MUSIC: return do_music_spell(spell, mode); + case REALM_HISSATSU: return do_hissatsu_spell(spell, mode); + case REALM_HEX: return do_hex_spell(spell, mode); + } + + return NULL; +} + + +/*! + * @brief 領域魔法の閲覧、学習、使用選択するインターフェイス処理 + * Allow user to choose a spell/prayer from the given book. + * @param sn 選択した魔法IDを返す参照ポインタ + * @param prompt 魔法を利用する際の動詞表記 + * @param sval 魔道書のsval + * @param learned 閲覧/使用選択ならばTRUE、学習処理ならFALSE + * @param use_realm 魔法領域ID + * @return + *
+ * If a valid spell is chosen, saves it in '*sn' and returns TRUE
+ * If the user hits escape, returns FALSE, and set '*sn' to -1
+ * If there are no legal choices, returns FALSE, and sets '*sn' to -2
+ * The "prompt" should be "cast", "recite", or "study"
+ * The "known" should be TRUE for cast/pray, FALSE for study
+ * 
+ */ +static int get_spell(SPELL_IDX *sn, concptr prompt, OBJECT_SUBTYPE_VALUE sval, bool learned, REALM_IDX use_realm) +{ + int i; + SPELL_IDX spell = -1; + int num = 0; + int ask = TRUE; + MANA_POINT need_mana; + SPELL_IDX spells[64]; + bool flag, redraw, okay; + char choice; + const magic_type *s_ptr; + char out_val[160]; + concptr p; + COMMAND_CODE code; +#ifdef JP + char jverb_buf[128]; +#endif + int menu_line = (use_menu ? 1 : 0); + + /* Get the spell, if available */ + if (repeat_pull(&code)) + { + *sn = (SPELL_IDX)code; + /* Verify the spell */ + if (spell_okay(*sn, learned, FALSE, use_realm)) + { + /* Success */ + return (TRUE); + } + } + + p = spell_category_name(mp_ptr->spell_book); + + /* Extract spells */ + for (spell = 0; spell < 32; spell++) + { + /* Check for this spell */ + if ((fake_spell_flags[sval] & (1L << spell))) + { + /* Collect this spell */ + spells[num++] = spell; + } + } + + /* Assume no usable spells */ + okay = FALSE; + + /* Assume no spells available */ + (*sn) = -2; + + /* Check for "okay" spells */ + for (i = 0; i < num; i++) + { + /* Look for "okay" spells */ + if (spell_okay(spells[i], learned, FALSE, use_realm)) okay = TRUE; + } + + /* No "okay" spells */ + if (!okay) return (FALSE); + if (((use_realm) != p_ptr->realm1) && ((use_realm) != p_ptr->realm2) && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) return FALSE; + if (((p_ptr->pclass == CLASS_SORCERER) || (p_ptr->pclass == CLASS_RED_MAGE)) && !is_magic(use_realm)) return FALSE; + if ((p_ptr->pclass == CLASS_RED_MAGE) && ((use_realm) != REALM_ARCANE) && (sval > 1)) return FALSE; + + /* Assume cancelled */ + *sn = (-1); + + /* Nothing chosen yet */ + flag = FALSE; + + /* No redraw yet */ + redraw = FALSE; + + p_ptr->window |= (PW_SPELL); + handle_stuff(); + + /* Build a prompt (accept all spells) */ +#ifdef JP + jverb(prompt, jverb_buf, JVERB_AND); + (void)strnfmt(out_val, 78, "(%^s:%c-%c, '*'で一覧, ESCで中断) どの%sを%^sますか? ", + p, I2A(0), I2A(num - 1), p, jverb_buf); +#else + (void)strnfmt(out_val, 78, "(%^ss %c-%c, *=List, ESC=exit) %^s which %s? ", + p, I2A(0), I2A(num - 1), prompt, p); +#endif + + /* Get a spell from the user */ + + choice = (always_show_list || use_menu) ? ESCAPE : 1; + while (!flag) + { + if (choice == ESCAPE) choice = ' '; + else if (!get_com(out_val, &choice, TRUE))break; + + if (use_menu && choice != ' ') + { + switch (choice) + { + case '0': + { + screen_load(); + return FALSE; + } + + case '8': + case 'k': + case 'K': + { + menu_line += (num - 1); + break; + } + + case '2': + case 'j': + case 'J': + { + menu_line++; + break; + } + + case 'x': + case 'X': + case '\r': + case '\n': + { + i = menu_line - 1; + ask = FALSE; + break; + } + } + if (menu_line > num) menu_line -= num; + /* Display a list of spells */ + print_spells(menu_line, spells, num, 1, 15, use_realm); + if (ask) continue; + } + else + { + /* Request redraw */ + if ((choice == ' ') || (choice == '*') || (choice == '?')) + { + /* Show the list */ + if (!redraw) + { + /* Show list */ + redraw = TRUE; + screen_save(); + + /* Display a list of spells */ + print_spells(menu_line, spells, num, 1, 15, use_realm); + } + + /* Hide the list */ + else + { + if (use_menu) continue; + + /* Hide list */ + redraw = FALSE; + screen_load(); + } + + /* Redo asking */ + continue; + } + + + /* Note verify */ + ask = (isupper(choice)); + + /* Lowercase */ + if (ask) choice = (char)tolower(choice); + + /* Extract request */ + i = (islower(choice) ? A2I(choice) : -1); + } + + /* Totally Illegal */ + if ((i < 0) || (i >= num)) + { + bell(); + continue; + } + + /* Save the spell index */ + spell = spells[i]; + + /* Require "okay" spells */ + if (!spell_okay(spell, learned, FALSE, use_realm)) + { + bell(); +#ifdef JP + msg_format("その%sを%sことはできません。", p, prompt); +#else + msg_format("You may not %s that %s.", prompt, p); +#endif + + continue; + } + + /* Verify it */ + if (ask) + { + char tmp_val[160]; + + /* Access the spell */ + if (!is_magic(use_realm)) + { + s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell]; + } + else + { + s_ptr = &mp_ptr->info[use_realm - 1][spell]; + } + + /* Extract mana consumption rate */ + if (use_realm == REALM_HISSATSU) + { + need_mana = s_ptr->smana; + } + else + { + need_mana = mod_need_mana(s_ptr->smana, spell, use_realm); + } + + /* Prompt */ +#ifdef JP + jverb(prompt, jverb_buf, JVERB_AND); + /* 英日切り替え機能に対応 */ + (void)strnfmt(tmp_val, 78, "%s(MP%d, 失敗率%d%%)を%sますか? ", + do_spell(use_realm, spell, SPELL_NAME), need_mana, + spell_chance(spell, use_realm), jverb_buf); +#else + (void)strnfmt(tmp_val, 78, "%^s %s (%d mana, %d%% fail)? ", + prompt, do_spell(use_realm, spell, SPELL_NAME), need_mana, + spell_chance(spell, use_realm)); +#endif + + + /* Belay that order */ + if (!get_check(tmp_val)) continue; + } + + /* Stop the loop */ + flag = TRUE; + } + + if (redraw) screen_load(); + + p_ptr->window |= (PW_SPELL); + handle_stuff(); + + /* Abort if needed */ + if (!flag) return FALSE; + + /* Save the choice */ + (*sn) = spell; + + repeat_push((COMMAND_CODE)spell); + + /* Success */ + return TRUE; +} + +/*! + * @brief プレイヤーの職業が練気術師の時、領域魔法と練気術を切り換える処理のインターフェイス + * @param browse_only 魔法と技能の閲覧を行うならばTRUE + * @return 魔道書を一冊も持っていないならTRUEを返す + */ +static void confirm_use_force(bool browse_only) +{ + char which; + COMMAND_CODE code; + + /* Get the item index */ + if (repeat_pull(&code) && (code == INVEN_FORCE)) + { + browse_only ? do_cmd_mind_browse() : do_cmd_mind(); + return; + } + + /* Show the prompt */ + prt(_("('w'練気術, ESC) 'w'かESCを押してください。 ", "(w for the Force, ESC) Hit 'w' or ESC. "), 0, 0); + + while (1) + { + /* Get a key */ + which = inkey(); + + if (which == ESCAPE) break; + else if (which == 'w') + { + repeat_push(INVEN_FORCE); + break; + } + } + + /* Clear the prompt line */ + prt("", 0, 0); + + if (which == 'w') + { + browse_only ? do_cmd_mind_browse() : do_cmd_mind(); + } +} + + +/*! + * @brief プレイヤーの魔法と技能を閲覧するコマンドのメインルーチン / + * Peruse the spells/prayers in a book + * @return なし + * @details + *
+ * Note that *all* spells in the book are listed
+ *
+ * Note that browsing is allowed while confused or blind,
+ * and in the dark, primarily to allow browsing in stores.
+ * 
+ */ +void do_cmd_browse(void) +{ + OBJECT_IDX item; + OBJECT_SUBTYPE_VALUE sval; + REALM_IDX use_realm = 0; + int j, line; + SPELL_IDX spell = -1; + int num = 0; + + SPELL_IDX spells[64]; + char temp[62 * 4]; + + object_type *o_ptr; + + concptr q, s; + + /* Warriors are illiterate */ + if (!(p_ptr->realm1 || p_ptr->realm2) && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) + { + msg_print(_("本を読むことができない!", "You cannot read books!")); + return; + } + + if (p_ptr->special_defense & KATA_MUSOU) + { + set_action(ACTION_NONE); + } + + if (p_ptr->pclass == CLASS_FORCETRAINER) + { + if (player_has_no_spellbooks()) + { + confirm_use_force(TRUE); + return; + } + } + + /* Restrict choices to "useful" books */ + if (p_ptr->realm2 == REALM_NONE) item_tester_tval = mp_ptr->spell_book; + else item_tester_hook = item_tester_learn_spell; + + q = _("どの本を読みますか? ", "Browse which book? "); + s = _("読める本がない。", "You have no books that you can read."); + + o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR | (p_ptr->pclass == CLASS_FORCETRAINER ? USE_FORCE : 0))); + if (!o_ptr) + { + if (item == INVEN_FORCE) /* the_force */ + { + do_cmd_mind_browse(); + return; + } + return; + } + + /* Access the item's sval */ + sval = o_ptr->sval; + + use_realm = tval2realm(o_ptr->tval); + + /* Track the object kind */ + object_kind_track(o_ptr->k_idx); + handle_stuff(); + + /* Extract spells */ + for (spell = 0; spell < 32; spell++) + { + /* Check for this spell */ + if ((fake_spell_flags[sval] & (1L << spell))) + { + /* Collect this spell */ + spells[num++] = spell; + } + } + + screen_save(); + prt("", 0, 0); + + /* Keep browsing spells. Exit browsing on cancel. */ + while (TRUE) + { + /* Ask for a spell, allow cancel */ + if (!get_spell(&spell, _("読む", "browse"), o_ptr->sval, TRUE, use_realm)) + { + /* If cancelled, leave immediately. */ + if (spell == -1) break; + + /* Display a list of spells */ + print_spells(0, spells, num, 1, 15, use_realm); + + /* Notify that there's nothing to see, and wait. */ + if (use_realm == REALM_HISSATSU) + prt(_("読める技がない。", "No techniques to browse."), 0, 0); + else + prt(_("読める呪文がない。", "No spells to browse."), 0, 0); + (void)inkey(); + + screen_load(); + + return; + } + + /* Clear lines, position cursor (really should use strlen here) */ + Term_erase(14, 14, 255); + Term_erase(14, 13, 255); + Term_erase(14, 12, 255); + Term_erase(14, 11, 255); + + roff_to_buf(do_spell(use_realm, spell, SPELL_DESC), 62, temp, sizeof(temp)); + + for (j = 0, line = 11; temp[j]; j += 1 + strlen(&temp[j])) + { + prt(&temp[j], line, 15); + line++; + } + } + screen_load(); +} + +/*! + * @brief プレイヤーの第二魔法領域を変更する / + * @param next_realm 変更先の魔法領域ID + * @return なし + */ +static void change_realm2(CHARACTER_IDX next_realm) +{ + int i, j = 0; + char tmp[80]; + + for (i = 0; i < 64; i++) + { + p_ptr->spell_order[j] = p_ptr->spell_order[i]; + if (p_ptr->spell_order[i] < 32) j++; + } + for (; j < 64; j++) + p_ptr->spell_order[j] = 99; + + for (i = 32; i < 64; i++) + { + p_ptr->spell_exp[i] = SPELL_EXP_UNSKILLED; + } + p_ptr->spell_learned2 = 0L; + p_ptr->spell_worked2 = 0L; + p_ptr->spell_forgotten2 = 0L; + + sprintf(tmp, _("魔法の領域を%sから%sに変更した。", "change magic realm from %s to %s."), realm_names[p_ptr->realm2], realm_names[next_realm]); + do_cmd_write_nikki(NIKKI_BUNSHOU, 0, tmp); + p_ptr->old_realm |= 1 << (p_ptr->realm2 - 1); + p_ptr->realm2 = next_realm; + + p_ptr->update |= (PU_REORDER); + p_ptr->update |= (PU_SPELLS); + handle_stuff(); + + /* Load an autopick preference file */ + autopick_load_pref(FALSE); +} + + +/*! + * @brief 魔法を学習するコマンドのメインルーチン / + * Study a book to gain a new spell/prayer + * @return なし + */ +void do_cmd_study(void) +{ + int i; + OBJECT_IDX item; + OBJECT_SUBTYPE_VALUE sval; + int increment = 0; + bool learned = FALSE; + + /* Spells of realm2 will have an increment of +32 */ + SPELL_IDX spell = -1; + + concptr p = spell_category_name(mp_ptr->spell_book); + + object_type *o_ptr; + + concptr q, s; + + if (!p_ptr->realm1) + { + msg_print(_("本を読むことができない!", "You cannot read books!")); + return; + } + + if (p_ptr->blind || no_lite()) + { + msg_print(_("目が見えない!", "You cannot see!")); + return; + } + + if (cmd_limit_confused(p_ptr)) return; + + if (!(p_ptr->new_spells)) + { + msg_format(_("新しい%sを覚えることはできない!", "You cannot learn any new %ss!"), p); + return; + } + + if (p_ptr->special_defense & KATA_MUSOU) + { + set_action(ACTION_NONE); + } + +#ifdef JP + if (p_ptr->new_spells < 10) { + msg_format("あと %d つの%sを学べる。", p_ptr->new_spells, p); + } + else { + msg_format("あと %d 個の%sを学べる。", p_ptr->new_spells, p); + } +#else + msg_format("You can learn %d new %s%s.", p_ptr->new_spells, p, + (p_ptr->new_spells == 1 ? "" : "s")); +#endif + + msg_print(NULL); + + + /* Restrict choices to "useful" books */ + if (p_ptr->realm2 == REALM_NONE) item_tester_tval = mp_ptr->spell_book; + else item_tester_hook = item_tester_learn_spell; + + q = _("どの本から学びますか? ", "Study which book? "); + s = _("読める本がない。", "You have no books that you can read."); + + o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); + if (!o_ptr) return; + + /* Access the item's sval */ + sval = o_ptr->sval; + + if (o_ptr->tval == REALM2_BOOK) increment = 32; + else if (o_ptr->tval != REALM1_BOOK) + { + if (!get_check(_("本当に魔法の領域を変更しますか?", "Really, change magic realm? "))) return; + change_realm2(tval2realm(o_ptr->tval)); + increment = 32; + } + + /* Track the object kind */ + object_kind_track(o_ptr->k_idx); + handle_stuff(); + + /* Mage -- Learn a selected spell */ + if (mp_ptr->spell_book != TV_LIFE_BOOK) + { + /* Ask for a spell, allow cancel */ + if (!get_spell(&spell, _("学ぶ", "study"), sval, FALSE, o_ptr->tval - TV_LIFE_BOOK + 1) && (spell == -1)) return; + } + + /* Priest -- Learn a random prayer */ + else + { + int k = 0; + int gift = -1; + + /* Extract spells */ + for (spell = 0; spell < 32; spell++) + { + /* Check spells in the book */ + if ((fake_spell_flags[sval] & (1L << spell))) + { + /* Skip non "okay" prayers */ + if (!spell_okay(spell, FALSE, TRUE, + (increment ? p_ptr->realm2 : p_ptr->realm1))) continue; + + /* Hack -- Prepare the randomizer */ + k++; + + /* Hack -- Apply the randomizer */ + if (one_in_(k)) gift = spell; + } + } + + /* Accept gift */ + spell = gift; + } + + /* Nothing to study */ + if (spell < 0) + { + msg_format(_("その本には学ぶべき%sがない。", "You cannot learn any %ss in that book."), p); + + /* Abort */ + return; + } + + if (increment) spell += increment; + + /* Learn the spell */ + if (spell < 32) + { + if (p_ptr->spell_learned1 & (1L << spell)) learned = TRUE; + else p_ptr->spell_learned1 |= (1L << spell); + } + else + { + if (p_ptr->spell_learned2 & (1L << (spell - 32))) learned = TRUE; + else p_ptr->spell_learned2 |= (1L << (spell - 32)); + } + + if (learned) + { + int max_exp = (spell < 32) ? SPELL_EXP_MASTER : SPELL_EXP_EXPERT; + int old_exp = p_ptr->spell_exp[spell]; + int new_rank = EXP_LEVEL_UNSKILLED; + concptr name = do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME); + + if (old_exp >= max_exp) + { + msg_format(_("その%sは完全に使いこなせるので学ぶ必要はない。", "You don't need to study this %s anymore."), p); + return; + } +#ifdef JP + if (!get_check(format("%sの%sをさらに学びます。よろしいですか?", name, p))) +#else + if (!get_check(format("You will study a %s of %s again. Are you sure? ", p, name))) +#endif + { + return; + } + else if (old_exp >= SPELL_EXP_EXPERT) + { + p_ptr->spell_exp[spell] = SPELL_EXP_MASTER; + new_rank = EXP_LEVEL_MASTER; + } + else if (old_exp >= SPELL_EXP_SKILLED) + { + if (spell >= 32) p_ptr->spell_exp[spell] = SPELL_EXP_EXPERT; + else p_ptr->spell_exp[spell] += SPELL_EXP_EXPERT - SPELL_EXP_SKILLED; + new_rank = EXP_LEVEL_EXPERT; + } + else if (old_exp >= SPELL_EXP_BEGINNER) + { + p_ptr->spell_exp[spell] = SPELL_EXP_SKILLED + (old_exp - SPELL_EXP_BEGINNER) * 2 / 3; + new_rank = EXP_LEVEL_SKILLED; + } + else + { + p_ptr->spell_exp[spell] = SPELL_EXP_BEGINNER + old_exp / 3; + new_rank = EXP_LEVEL_BEGINNER; + } + msg_format(_("%sの熟練度が%sに上がった。", "Your proficiency of %s is now %s rank."), name, exp_level_str[new_rank]); + } + else + { + /* Find the next open entry in "p_ptr->spell_order[]" */ + for (i = 0; i < 64; i++) + { + /* Stop at the first empty space */ + if (p_ptr->spell_order[i] == 99) break; + } + + /* Add the spell to the known list */ + p_ptr->spell_order[i++] = spell; + + /* Mention the result */ +#ifdef JP + /* 英日切り替え機能に対応 */ + if (mp_ptr->spell_book == TV_MUSIC_BOOK) + { + msg_format("%sを学んだ。", + do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME)); + } + else + { + msg_format("%sの%sを学んだ。", + do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME), p); + } +#else + msg_format("You have learned the %s of %s.", + p, do_spell(increment ? p_ptr->realm2 : p_ptr->realm1, spell % 32, SPELL_NAME)); +#endif + } + + take_turn(p_ptr, 100);; + + switch (mp_ptr->spell_book) + { + case TV_LIFE_BOOK: + chg_virtue(V_FAITH, 1); + break; + case TV_DEATH_BOOK: + chg_virtue(V_UNLIFE, 1); + break; + case TV_NATURE_BOOK: + chg_virtue(V_NATURE, 1); + break; + default: + chg_virtue(V_KNOWLEDGE, 1); + break; + } + + sound(SOUND_STUDY); + + /* One less spell available */ + p_ptr->learned_spells++; + + /* Update Study */ + p_ptr->update |= (PU_SPELLS); + update_creature(p_ptr); + + /* Redraw object recall */ + p_ptr->window |= (PW_OBJECT); +} + + +/*! + * @brief 魔法を詠唱するコマンドのメインルーチン / + * Cast a spell + * @return なし + */ +void do_cmd_cast(void) +{ + OBJECT_IDX item; + OBJECT_SUBTYPE_VALUE sval; + SPELL_IDX spell; + REALM_IDX realm; + int chance; + int increment = 0; + REALM_IDX use_realm; + MANA_POINT need_mana; + + concptr prayer; + object_type *o_ptr; + const magic_type *s_ptr; + concptr q, s; + + bool over_exerted = FALSE; + + /* Require spell ability */ + if (!p_ptr->realm1 && (p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE)) + { + msg_print(_("呪文を唱えられない!", "You cannot cast spells!")); + return; + } + + /* Require lite */ + if (p_ptr->blind || no_lite()) + { + if (p_ptr->pclass == CLASS_FORCETRAINER) confirm_use_force(FALSE); + else + { + msg_print(_("目が見えない!", "You cannot see!")); + flush(); + } + return; + } + + if (cmd_limit_confused(p_ptr)) return; + + /* Hex */ + if (p_ptr->realm1 == REALM_HEX) + { + if (hex_spell_fully()) + { + bool flag = FALSE; + msg_print(_("これ以上新しい呪文を詠唱することはできない。", "Can not spell new spells more.")); + flush(); + if (p_ptr->lev >= 35) flag = stop_hex_spell(); + if (!flag) return; + } + } + + if (p_ptr->pclass == CLASS_FORCETRAINER) + { + if (player_has_no_spellbooks()) + { + confirm_use_force(FALSE); + return; + } + } + + prayer = spell_category_name(mp_ptr->spell_book); + + /* Restrict choices to spell books */ + item_tester_tval = mp_ptr->spell_book; + + q = _("どの呪文書を使いますか? ", "Use which book? "); + s = _("呪文書がない!", "You have no spell books!"); + + o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR | (p_ptr->pclass == CLASS_FORCETRAINER ? USE_FORCE : 0))); + if (!o_ptr) + { + if (item == INVEN_FORCE) /* the_force */ + { + do_cmd_mind(); + return; + } + return; + } + + /* Access the item's sval */ + sval = o_ptr->sval; + + if ((p_ptr->pclass != CLASS_SORCERER) && (p_ptr->pclass != CLASS_RED_MAGE) && (o_ptr->tval == REALM2_BOOK)) increment = 32; + + /* Track the object kind */ + object_kind_track(o_ptr->k_idx); + handle_stuff(); + + if ((p_ptr->pclass == CLASS_SORCERER) || (p_ptr->pclass == CLASS_RED_MAGE)) + realm = o_ptr->tval - TV_LIFE_BOOK + 1; + else if (increment) realm = p_ptr->realm2; + else realm = p_ptr->realm1; + + /* Ask for a spell */ +#ifdef JP + if (!get_spell(&spell, ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "詠唱する" : (mp_ptr->spell_book == TV_MUSIC_BOOK) ? "歌う" : "唱える"), + sval, TRUE, realm)) + { + if (spell == -2) msg_format("その本には知っている%sがない。", prayer); + return; + } +#else + if (!get_spell(&spell, ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "recite" : "cast"), + sval, TRUE, realm)) + { + if (spell == -2) + msg_format("You don't know any %ss in that book.", prayer); + return; + } +#endif + + + use_realm = tval2realm(o_ptr->tval); + + /* Hex */ + if (use_realm == REALM_HEX) + { + if (hex_spelling(spell)) + { + msg_print(_("その呪文はすでに詠唱中だ。", "You are already casting it.")); + return; + } + } + + if (!is_magic(use_realm)) + { + s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell]; + } + else + { + s_ptr = &mp_ptr->info[realm - 1][spell]; + } + + /* Extract mana consumption rate */ + need_mana = mod_need_mana(s_ptr->smana, spell, realm); + + /* Verify "dangerous" spells */ + if (need_mana > p_ptr->csp) + { + if (flush_failure) flush(); + + /* Warning */ +#ifdef JP + msg_format("その%sを%sのに十分なマジックポイントがない。", prayer, + ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "詠唱する" : (mp_ptr->spell_book == TV_LIFE_BOOK) ? "歌う" : "唱える")); +#else + msg_format("You do not have enough mana to %s this %s.", + ((mp_ptr->spell_book == TV_LIFE_BOOK) ? "recite" : "cast"), + prayer); +#endif + + + if (!over_exert) return; + + /* Verify */ + if (!get_check_strict(_("それでも挑戦しますか? ", "Attempt it anyway? "), CHECK_OKAY_CANCEL)) return; + } + + /* Spell failure chance */ + chance = spell_chance(spell, use_realm); + + /* Sufficient mana */ + if (need_mana <= p_ptr->csp) + { + /* Use some mana */ + p_ptr->csp -= need_mana; + } + else over_exerted = TRUE; + p_ptr->redraw |= (PR_MANA); + + /* Failed spell */ + if (randint0(100) < chance) + { + if (flush_failure) flush(); + + msg_format(_("%sをうまく唱えられなかった!", "You failed to get the %s off!"), prayer); + sound(SOUND_FAIL); + + switch (realm) + { + case REALM_LIFE: + if (randint1(100) < chance) chg_virtue(V_VITALITY, -1); + break; + case REALM_DEATH: + if (randint1(100) < chance) chg_virtue(V_UNLIFE, -1); + break; + case REALM_NATURE: + if (randint1(100) < chance) chg_virtue(V_NATURE, -1); + break; + case REALM_DAEMON: + if (randint1(100) < chance) chg_virtue(V_JUSTICE, 1); + break; + case REALM_CRUSADE: + if (randint1(100) < chance) chg_virtue(V_JUSTICE, -1); + break; + case REALM_HEX: + if (randint1(100) < chance) chg_virtue(V_COMPASSION, -1); + break; + default: + if (randint1(100) < chance) chg_virtue(V_KNOWLEDGE, -1); + break; + } + + /* Failure casting may activate some side effect */ + do_spell(realm, spell, SPELL_FAIL); + + + if ((o_ptr->tval == TV_CHAOS_BOOK) && (randint1(100) < spell)) + { + msg_print(_("カオス的な効果を発生した!", "You produce a chaotic effect!")); + wild_magic(spell); + } + else if ((o_ptr->tval == TV_DEATH_BOOK) && (randint1(100) < spell)) + { + if ((sval == 3) && one_in_(2)) + { + sanity_blast(0, TRUE); + } + else + { + msg_print(_("痛い!", "It hurts!")); + take_hit(DAMAGE_LOSELIFE, damroll(o_ptr->sval + 1, 6), _("暗黒魔法の逆流", "a miscast Death spell"), -1); + + if ((spell > 15) && one_in_(6) && !p_ptr->hold_exp) + lose_exp(spell * 250); + } + } + else if ((o_ptr->tval == TV_MUSIC_BOOK) && (randint1(200) < spell)) + { + msg_print(_("いやな音が響いた", "An infernal sound echoed.")); + aggravate_monsters(0); + } + if (randint1(100) >= chance) + chg_virtue(V_CHANCE, -1); + } + + /* Process spell */ + else + { + /* Canceled spells cost neither a turn nor mana */ + if (!do_spell(realm, spell, SPELL_CAST)) return; + + if (randint1(100) < chance) + chg_virtue(V_CHANCE, 1); + + /* A spell was cast */ + if (!(increment ? + (p_ptr->spell_worked2 & (1L << spell)) : + (p_ptr->spell_worked1 & (1L << spell))) + && (p_ptr->pclass != CLASS_SORCERER) + && (p_ptr->pclass != CLASS_RED_MAGE)) + { + int e = s_ptr->sexp; + + /* The spell worked */ + if (realm == p_ptr->realm1) + { + p_ptr->spell_worked1 |= (1L << spell); + } + else + { + p_ptr->spell_worked2 |= (1L << spell); + } + + /* Gain experience */ + gain_exp(e * s_ptr->slevel); + + /* Redraw object recall */ + p_ptr->window |= (PW_OBJECT); + + switch (realm) + { + case REALM_LIFE: + chg_virtue(V_TEMPERANCE, 1); + chg_virtue(V_COMPASSION, 1); + chg_virtue(V_VITALITY, 1); + chg_virtue(V_DILIGENCE, 1); + break; + case REALM_DEATH: + chg_virtue(V_UNLIFE, 1); + chg_virtue(V_JUSTICE, -1); + chg_virtue(V_FAITH, -1); + chg_virtue(V_VITALITY, -1); + break; + case REALM_DAEMON: + chg_virtue(V_JUSTICE, -1); + chg_virtue(V_FAITH, -1); + chg_virtue(V_HONOUR, -1); + chg_virtue(V_TEMPERANCE, -1); + break; + case REALM_CRUSADE: + chg_virtue(V_FAITH, 1); + chg_virtue(V_JUSTICE, 1); + chg_virtue(V_SACRIFICE, 1); + chg_virtue(V_HONOUR, 1); + break; + case REALM_NATURE: + chg_virtue(V_NATURE, 1); + chg_virtue(V_HARMONY, 1); + break; + case REALM_HEX: + chg_virtue(V_JUSTICE, -1); + chg_virtue(V_FAITH, -1); + chg_virtue(V_HONOUR, -1); + chg_virtue(V_COMPASSION, -1); + break; + default: + chg_virtue(V_KNOWLEDGE, 1); + break; + } + } + switch (realm) + { + case REALM_LIFE: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_TEMPERANCE, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_COMPASSION, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_VITALITY, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_DILIGENCE, 1); + break; + case REALM_DEATH: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_UNLIFE, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_VITALITY, -1); + break; + case REALM_DAEMON: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_TEMPERANCE, -1); + break; + case REALM_CRUSADE: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_SACRIFICE, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, 1); + break; + case REALM_NATURE: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_NATURE, 1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HARMONY, 1); + break; + case REALM_HEX: + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_JUSTICE, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_FAITH, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_HONOUR, -1); + if (randint1(100 + p_ptr->lev) < need_mana) chg_virtue(V_COMPASSION, -1); + break; + } + if (mp_ptr->spell_xtra & MAGIC_GAIN_EXP) + { + s16b cur_exp = p_ptr->spell_exp[(increment ? 32 : 0) + spell]; + s16b exp_gain = 0; + + if (cur_exp < SPELL_EXP_BEGINNER) + exp_gain += 60; + else if (cur_exp < SPELL_EXP_SKILLED) + { + if ((dun_level > 4) && ((dun_level + 10) > p_ptr->lev)) + exp_gain = 8; + } + else if (cur_exp < SPELL_EXP_EXPERT) + { + if (((dun_level + 5) > p_ptr->lev) && ((dun_level + 5) > s_ptr->slevel)) + exp_gain = 2; + } + else if ((cur_exp < SPELL_EXP_MASTER) && !increment) + { + if (((dun_level + 5) > p_ptr->lev) && (dun_level > s_ptr->slevel)) + exp_gain = 1; + } + p_ptr->spell_exp[(increment ? 32 : 0) + spell] += exp_gain; + } + } + + take_turn(p_ptr, 100);; + + + /* Over-exert the player */ + if (over_exerted) + { + int oops = need_mana; + + /* No mana left */ + p_ptr->csp = 0; + p_ptr->csp_frac = 0; + + msg_print(_("精神を集中しすぎて気を失ってしまった!", "You faint from the effort!")); + + /* Hack -- Bypass free action */ + (void)set_paralyzed(p_ptr->paralyzed + randint1(5 * oops + 1)); + + switch (realm) + { + case REALM_LIFE: + chg_virtue(V_VITALITY, -10); + break; + case REALM_DEATH: + chg_virtue(V_UNLIFE, -10); + break; + case REALM_DAEMON: + chg_virtue(V_JUSTICE, 10); + break; + case REALM_NATURE: + chg_virtue(V_NATURE, -10); + break; + case REALM_CRUSADE: + chg_virtue(V_JUSTICE, -10); + break; + case REALM_HEX: + chg_virtue(V_COMPASSION, 10); + break; + default: + chg_virtue(V_KNOWLEDGE, -10); + break; + } + + /* Damage CON (possibly permanently) */ + if (randint0(100) < 50) + { + bool perm = (randint0(100) < 25); + + msg_print(_("体を悪くしてしまった!", "You have damaged your health!")); + + /* Reduce constitution */ + (void)dec_stat(A_CON, 15 + randint1(10), perm); + } + } + + p_ptr->window |= (PW_PLAYER); + p_ptr->window |= (PW_SPELL); +} diff --git a/src/cmd-spell.h b/src/cmd-spell.h index beacfd580..9e1ebefc2 100644 --- a/src/cmd-spell.h +++ b/src/cmd-spell.h @@ -1,24 +1,24 @@ -#define KWD_DAM _("損傷:", "dam ") -#define KWD_RANGE _("射程:", "rng ") -#define KWD_DURATION _("期間:", "dur ") -#define KWD_SPHERE _("範囲:", "range ") -#define KWD_HEAL _("回復:", "heal ") -#define KWD_RANDOM _("ランダム", "random") - -extern concptr info_string_dice(concptr str, DICE_NUMBER dice, DICE_SID sides, int base); -extern concptr info_damage(DICE_NUMBER dice, DICE_SID sides, int base); -extern concptr info_duration(int base, DICE_SID sides); -extern concptr info_range(POSITION range); -extern concptr info_heal(DICE_NUMBER dice, DICE_SID sides, int base); -extern concptr info_delay(int base, DICE_SID sides); -extern concptr info_multi_damage(HIT_POINT dam); -extern concptr info_multi_damage_dice(DICE_NUMBER dice, DICE_SID sides); -extern concptr info_power(int power); -extern concptr info_power_dice(DICE_NUMBER dice, DICE_SID sides); -extern concptr info_radius(POSITION rad); -extern concptr info_weight(WEIGHT weight); - -/* cmd5.c */ -extern void do_cmd_browse(void); -extern void do_cmd_study(void); -extern void do_cmd_cast(void); +#define KWD_DAM _("損傷:", "dam ") +#define KWD_RANGE _("射程:", "rng ") +#define KWD_DURATION _("期間:", "dur ") +#define KWD_SPHERE _("範囲:", "range ") +#define KWD_HEAL _("回復:", "heal ") +#define KWD_RANDOM _("ランダム", "random") + +extern concptr info_string_dice(concptr str, DICE_NUMBER dice, DICE_SID sides, int base); +extern concptr info_damage(DICE_NUMBER dice, DICE_SID sides, int base); +extern concptr info_duration(int base, DICE_SID sides); +extern concptr info_range(POSITION range); +extern concptr info_heal(DICE_NUMBER dice, DICE_SID sides, int base); +extern concptr info_delay(int base, DICE_SID sides); +extern concptr info_multi_damage(HIT_POINT dam); +extern concptr info_multi_damage_dice(DICE_NUMBER dice, DICE_SID sides); +extern concptr info_power(int power); +extern concptr info_power_dice(DICE_NUMBER dice, DICE_SID sides); +extern concptr info_radius(POSITION rad); +extern concptr info_weight(WEIGHT weight); + +/* cmd5.c */ +extern void do_cmd_browse(void); +extern void do_cmd_study(void); +extern void do_cmd_cast(void); diff --git a/src/cmd-usestaff.c b/src/cmd-usestaff.c index aa088d171..a78de2d54 100644 --- a/src/cmd-usestaff.c +++ b/src/cmd-usestaff.c @@ -1,447 +1,447 @@ -#include "angband.h" -#include "projection.h" -#include "spells-summon.h" -#include "avatar.h" -#include "player-status.h" -#include "spells-status.h" - - - -/*! -* @brief 杖の効果を発動する -* @param sval オブジェクトのsval -* @param use_charge 使用回数を消費したかどうかを返す参照ポインタ -* @param powerful 強力発動上の処理ならばTRUE -* @param magic 魔道具術上の処理ならばTRUE -* @param known 判明済ならばTRUE -* @return 発動により効果内容が確定したならばTRUEを返す -*/ -int staff_effect(OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known) -{ - int k; - int ident = FALSE; - PLAYER_LEVEL lev = powerful ? p_ptr->lev * 2 : p_ptr->lev; - POSITION detect_rad = powerful ? DETECT_RAD_DEFAULT * 3 / 2 : DETECT_RAD_DEFAULT; - - /* Analyze the staff */ - switch (sval) - { - case SV_STAFF_DARKNESS: - { - if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark)) - { - if (set_blind(p_ptr->blind + 3 + randint1(5))) ident = TRUE; - } - if (unlite_area(10, (powerful ? 6 : 3))) ident = TRUE; - break; - } - - case SV_STAFF_SLOWNESS: - { - if (set_slow(p_ptr->slow + randint1(30) + 15, FALSE)) ident = TRUE; - break; - } - - case SV_STAFF_HASTE_MONSTERS: - { - if (speed_monsters()) ident = TRUE; - break; - } - - case SV_STAFF_SUMMONING: - { - const int times = randint1(powerful ? 8 : 4); - for (k = 0; k < times; k++) - { - if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) - { - ident = TRUE; - } - } - break; - } - - case SV_STAFF_TELEPORTATION: - { - teleport_player((powerful ? 150 : 100), 0L); - ident = TRUE; - break; - } - - case SV_STAFF_IDENTIFY: - { - if (powerful) { - if (!identify_fully(FALSE)) *use_charge = FALSE; - } - else { - if (!ident_spell(FALSE)) *use_charge = FALSE; - } - ident = TRUE; - break; - } - - case SV_STAFF_REMOVE_CURSE: - { - bool result = powerful ? remove_all_curse() : remove_curse(); - if (result) - { - ident = TRUE; - } - break; - } - - case SV_STAFF_STARLITE: - ident = starlight(magic); - break; - - case SV_STAFF_LITE: - { - if (lite_area(damroll(2, 8), (powerful ? 4 : 2))) ident = TRUE; - break; - } - - case SV_STAFF_MAPPING: - { - map_area(powerful ? DETECT_RAD_MAP * 3 / 2 : DETECT_RAD_MAP); - ident = TRUE; - break; - } - - case SV_STAFF_DETECT_GOLD: - { - if (detect_treasure(detect_rad)) ident = TRUE; - if (detect_objects_gold(detect_rad)) ident = TRUE; - break; - } - - case SV_STAFF_DETECT_ITEM: - { - if (detect_objects_normal(detect_rad)) ident = TRUE; - break; - } - - case SV_STAFF_DETECT_TRAP: - { - if (detect_traps(detect_rad, known)) ident = TRUE; - break; - } - - case SV_STAFF_DETECT_DOOR: - { - if (detect_doors(detect_rad)) ident = TRUE; - if (detect_stairs(detect_rad)) ident = TRUE; - break; - } - - case SV_STAFF_DETECT_INVIS: - { - if (detect_monsters_invis(detect_rad)) ident = TRUE; - break; - } - - case SV_STAFF_DETECT_EVIL: - { - if (detect_monsters_evil(detect_rad)) ident = TRUE; - break; - } - - case SV_STAFF_CURE_LIGHT: - { - ident = cure_light_wounds((powerful ? 4 : 2), 8); - break; - } - - case SV_STAFF_CURING: - { - ident = true_healing(0); - if (set_shero(0, TRUE)) ident = TRUE; - break; - } - - case SV_STAFF_HEALING: - { - if (cure_critical_wounds(powerful ? 500 : 300)) ident = TRUE; - break; - } - - case SV_STAFF_THE_MAGI: - { - if (do_res_stat(A_INT)) ident = TRUE; - ident |= restore_mana(FALSE); - if (set_shero(0, TRUE)) ident = TRUE; - break; - } - - case SV_STAFF_SLEEP_MONSTERS: - { - if (sleep_monsters(lev)) ident = TRUE; - break; - } - - case SV_STAFF_SLOW_MONSTERS: - { - if (slow_monsters(lev)) ident = TRUE; - break; - } - - case SV_STAFF_SPEED: - { - if (set_fast(randint1(30) + (powerful ? 30 : 15), FALSE)) ident = TRUE; - break; - } - - case SV_STAFF_PROBING: - { - ident = probing(); - break; - } - - case SV_STAFF_DISPEL_EVIL: - { - ident = dispel_evil(powerful ? 120 : 80); - break; - } - - case SV_STAFF_POWER: - { - ident = dispel_monsters(powerful ? 225 : 150) ; - break; - } - - case SV_STAFF_HOLINESS: - { - ident = cleansing_nova(p_ptr, magic, powerful); - break; - } - - case SV_STAFF_GENOCIDE: - { - ident = symbol_genocide((magic ? lev + 50 : 200), TRUE); - break; - } - - case SV_STAFF_EARTHQUAKES: - { - if (earthquake(p_ptr->y, p_ptr->x, (powerful ? 15 : 10))) - ident = TRUE; - else - msg_print(_("ダンジョンが揺れた。", "The dungeon trembles.")); - - break; - } - - case SV_STAFF_DESTRUCTION: - { - ident = destroy_area(p_ptr->y, p_ptr->x, (powerful ? 18 : 13) + randint0(5), FALSE); - break; - } - - case SV_STAFF_ANIMATE_DEAD: - { - ident = animate_dead(0, p_ptr->y, p_ptr->x); - break; - } - - case SV_STAFF_MSTORM: - { - ident = unleash_mana_storm(p_ptr, powerful); - break; - } - - case SV_STAFF_NOTHING: - { - msg_print(_("何も起らなかった。", "Nothing happen.")); - if (prace_is_(RACE_SKELETON) || prace_is_(RACE_GOLEM) || - prace_is_(RACE_ZOMBIE) || prace_is_(RACE_SPECTRE)) - msg_print(_("もったいない事をしたような気がする。食べ物は大切にしなくては。", "What a waste. It's your food!")); - break; - } - } - return ident; -} - -/*! - * @brief 杖を使うコマンドのサブルーチン / - * Use a staff. -RAK- - * @param item 使うオブジェクトの所持品ID - * @return なし - * @details - * One charge of one staff disappears. - * Hack -- staffs of identify can be "cancelled". - */ -void do_cmd_use_staff_aux(INVENTORY_IDX item) -{ - int ident, chance, lev; - object_type *o_ptr; - - - /* Hack -- let staffs of identify get aborted */ - bool use_charge = TRUE; - - - /* Get the item (in the pack) */ - if (item >= 0) - { - o_ptr = &inventory[item]; - } - - /* Get the item (on the floor) */ - else - { - o_ptr = &o_list[0 - item]; - } - - - /* Mega-Hack -- refuse to use a pile from the ground */ - if ((item < 0) && (o_ptr->number > 1)) - { - msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs.")); - return; - } - - - take_turn(p_ptr, 100);; - - /* Extract the item level */ - lev = k_info[o_ptr->k_idx].level; - if (lev > 50) lev = 50 + (lev - 50) / 2; - - /* Base chance of success */ - chance = p_ptr->skill_dev; - - /* Confusion hurts skill */ - if (p_ptr->confused) chance = chance / 2; - - /* Hight level objects are harder */ - chance = chance - lev; - - /* Give everyone a (slight) chance */ - if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1)) - { - chance = USE_DEVICE; - } - - if (cmd_limit_time_walk(p_ptr)) return; - - /* Roll for usage */ - if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER)) - { - if (flush_failure) flush(); - msg_print(_("杖をうまく使えなかった。", "You failed to use the staff properly.")); - sound(SOUND_FAIL); - return; - } - - /* Notice empty staffs */ - if (o_ptr->pval <= 0) - { - if (flush_failure) flush(); - msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left.")); - o_ptr->ident |= (IDENT_EMPTY); - p_ptr->update |= (PU_COMBINE | PU_REORDER); - p_ptr->window |= (PW_INVEN); - - return; - } - - - sound(SOUND_ZAP); - - ident = staff_effect(o_ptr->sval, &use_charge, FALSE, FALSE, object_is_aware(o_ptr)); - - if (!(object_is_aware(o_ptr))) - { - chg_virtue(V_PATIENCE, -1); - chg_virtue(V_CHANCE, 1); - chg_virtue(V_KNOWLEDGE, -1); - } - p_ptr->update |= (PU_COMBINE | PU_REORDER); - - /* Tried the item */ - object_tried(o_ptr); - - /* An identification was made */ - if (ident && !object_is_aware(o_ptr)) - { - object_aware(o_ptr); - gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); - } - - p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); - - - /* Hack -- some uses are "free" */ - if (!use_charge) return; - - - /* Use a single charge */ - o_ptr->pval--; - - /* XXX Hack -- unstack if necessary */ - if ((item >= 0) && (o_ptr->number > 1)) - { - object_type forge; - object_type *q_ptr; - q_ptr = &forge; - - /* Obtain a local object */ - object_copy(q_ptr, o_ptr); - - /* Modify quantity */ - q_ptr->number = 1; - - /* Restore the charges */ - o_ptr->pval++; - - /* Unstack the used item */ - o_ptr->number--; - p_ptr->total_weight -= q_ptr->weight; - item = inven_carry(q_ptr); - - msg_print(_("杖をまとめなおした。", "You unstack your staff.")); - } - - /* Describe charges in the pack */ - if (item >= 0) - { - inven_item_charges(item); - } - - /* Describe charges on the floor */ - else - { - floor_item_charges(0 - item); - } -} - -/*! -* @brief 杖を使うコマンドのメインルーチン / -* @return なし -*/ -void do_cmd_use_staff(void) -{ - OBJECT_IDX item; - concptr q, s; - - if (p_ptr->wild_mode) - { - return; - } - - if (cmd_limit_arena(p_ptr)) return; - - if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) - { - set_action(ACTION_NONE); - } - - /* Restrict choices to wands */ - item_tester_tval = TV_STAFF; - - q = _("どの杖を使いますか? ", "Use which staff? "); - s = _("使える杖がない。", "You have no staff to use."); - - if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; - - do_cmd_use_staff_aux(item); -} +#include "angband.h" +#include "projection.h" +#include "spells-summon.h" +#include "avatar.h" +#include "player-status.h" +#include "spells-status.h" + + + +/*! +* @brief 杖の効果を発動する +* @param sval オブジェクトのsval +* @param use_charge 使用回数を消費したかどうかを返す参照ポインタ +* @param powerful 強力発動上の処理ならばTRUE +* @param magic 魔道具術上の処理ならばTRUE +* @param known 判明済ならばTRUE +* @return 発動により効果内容が確定したならばTRUEを返す +*/ +int staff_effect(OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known) +{ + int k; + int ident = FALSE; + PLAYER_LEVEL lev = powerful ? p_ptr->lev * 2 : p_ptr->lev; + POSITION detect_rad = powerful ? DETECT_RAD_DEFAULT * 3 / 2 : DETECT_RAD_DEFAULT; + + /* Analyze the staff */ + switch (sval) + { + case SV_STAFF_DARKNESS: + { + if (!(p_ptr->resist_blind) && !(p_ptr->resist_dark)) + { + if (set_blind(p_ptr->blind + 3 + randint1(5))) ident = TRUE; + } + if (unlite_area(10, (powerful ? 6 : 3))) ident = TRUE; + break; + } + + case SV_STAFF_SLOWNESS: + { + if (set_slow(p_ptr->slow + randint1(30) + 15, FALSE)) ident = TRUE; + break; + } + + case SV_STAFF_HASTE_MONSTERS: + { + if (speed_monsters()) ident = TRUE; + break; + } + + case SV_STAFF_SUMMONING: + { + const int times = randint1(powerful ? 8 : 4); + for (k = 0; k < times; k++) + { + if (summon_specific(0, p_ptr->y, p_ptr->x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0')) + { + ident = TRUE; + } + } + break; + } + + case SV_STAFF_TELEPORTATION: + { + teleport_player((powerful ? 150 : 100), 0L); + ident = TRUE; + break; + } + + case SV_STAFF_IDENTIFY: + { + if (powerful) { + if (!identify_fully(FALSE)) *use_charge = FALSE; + } + else { + if (!ident_spell(FALSE)) *use_charge = FALSE; + } + ident = TRUE; + break; + } + + case SV_STAFF_REMOVE_CURSE: + { + bool result = powerful ? remove_all_curse() : remove_curse(); + if (result) + { + ident = TRUE; + } + break; + } + + case SV_STAFF_STARLITE: + ident = starlight(magic); + break; + + case SV_STAFF_LITE: + { + if (lite_area(damroll(2, 8), (powerful ? 4 : 2))) ident = TRUE; + break; + } + + case SV_STAFF_MAPPING: + { + map_area(powerful ? DETECT_RAD_MAP * 3 / 2 : DETECT_RAD_MAP); + ident = TRUE; + break; + } + + case SV_STAFF_DETECT_GOLD: + { + if (detect_treasure(detect_rad)) ident = TRUE; + if (detect_objects_gold(detect_rad)) ident = TRUE; + break; + } + + case SV_STAFF_DETECT_ITEM: + { + if (detect_objects_normal(detect_rad)) ident = TRUE; + break; + } + + case SV_STAFF_DETECT_TRAP: + { + if (detect_traps(detect_rad, known)) ident = TRUE; + break; + } + + case SV_STAFF_DETECT_DOOR: + { + if (detect_doors(detect_rad)) ident = TRUE; + if (detect_stairs(detect_rad)) ident = TRUE; + break; + } + + case SV_STAFF_DETECT_INVIS: + { + if (detect_monsters_invis(detect_rad)) ident = TRUE; + break; + } + + case SV_STAFF_DETECT_EVIL: + { + if (detect_monsters_evil(detect_rad)) ident = TRUE; + break; + } + + case SV_STAFF_CURE_LIGHT: + { + ident = cure_light_wounds((powerful ? 4 : 2), 8); + break; + } + + case SV_STAFF_CURING: + { + ident = true_healing(0); + if (set_shero(0, TRUE)) ident = TRUE; + break; + } + + case SV_STAFF_HEALING: + { + if (cure_critical_wounds(powerful ? 500 : 300)) ident = TRUE; + break; + } + + case SV_STAFF_THE_MAGI: + { + if (do_res_stat(A_INT)) ident = TRUE; + ident |= restore_mana(FALSE); + if (set_shero(0, TRUE)) ident = TRUE; + break; + } + + case SV_STAFF_SLEEP_MONSTERS: + { + if (sleep_monsters(lev)) ident = TRUE; + break; + } + + case SV_STAFF_SLOW_MONSTERS: + { + if (slow_monsters(lev)) ident = TRUE; + break; + } + + case SV_STAFF_SPEED: + { + if (set_fast(randint1(30) + (powerful ? 30 : 15), FALSE)) ident = TRUE; + break; + } + + case SV_STAFF_PROBING: + { + ident = probing(); + break; + } + + case SV_STAFF_DISPEL_EVIL: + { + ident = dispel_evil(powerful ? 120 : 80); + break; + } + + case SV_STAFF_POWER: + { + ident = dispel_monsters(powerful ? 225 : 150) ; + break; + } + + case SV_STAFF_HOLINESS: + { + ident = cleansing_nova(p_ptr, magic, powerful); + break; + } + + case SV_STAFF_GENOCIDE: + { + ident = symbol_genocide((magic ? lev + 50 : 200), TRUE); + break; + } + + case SV_STAFF_EARTHQUAKES: + { + if (earthquake(p_ptr->y, p_ptr->x, (powerful ? 15 : 10))) + ident = TRUE; + else + msg_print(_("ダンジョンが揺れた。", "The dungeon trembles.")); + + break; + } + + case SV_STAFF_DESTRUCTION: + { + ident = destroy_area(p_ptr->y, p_ptr->x, (powerful ? 18 : 13) + randint0(5), FALSE); + break; + } + + case SV_STAFF_ANIMATE_DEAD: + { + ident = animate_dead(0, p_ptr->y, p_ptr->x); + break; + } + + case SV_STAFF_MSTORM: + { + ident = unleash_mana_storm(p_ptr, powerful); + break; + } + + case SV_STAFF_NOTHING: + { + msg_print(_("何も起らなかった。", "Nothing happen.")); + if (prace_is_(RACE_SKELETON) || prace_is_(RACE_GOLEM) || + prace_is_(RACE_ZOMBIE) || prace_is_(RACE_SPECTRE)) + msg_print(_("もったいない事をしたような気がする。食べ物は大切にしなくては。", "What a waste. It's your food!")); + break; + } + } + return ident; +} + +/*! + * @brief 杖を使うコマンドのサブルーチン / + * Use a staff. -RAK- + * @param item 使うオブジェクトの所持品ID + * @return なし + * @details + * One charge of one staff disappears. + * Hack -- staffs of identify can be "cancelled". + */ +void do_cmd_use_staff_aux(INVENTORY_IDX item) +{ + int ident, chance, lev; + object_type *o_ptr; + + + /* Hack -- let staffs of identify get aborted */ + bool use_charge = TRUE; + + + /* Get the item (in the pack) */ + if (item >= 0) + { + o_ptr = &inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + o_ptr = &o_list[0 - item]; + } + + + /* Mega-Hack -- refuse to use a pile from the ground */ + if ((item < 0) && (o_ptr->number > 1)) + { + msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs.")); + return; + } + + + take_turn(p_ptr, 100);; + + /* Extract the item level */ + lev = k_info[o_ptr->k_idx].level; + if (lev > 50) lev = 50 + (lev - 50) / 2; + + /* Base chance of success */ + chance = p_ptr->skill_dev; + + /* Confusion hurts skill */ + if (p_ptr->confused) chance = chance / 2; + + /* Hight level objects are harder */ + chance = chance - lev; + + /* Give everyone a (slight) chance */ + if ((chance < USE_DEVICE) && one_in_(USE_DEVICE - chance + 1)) + { + chance = USE_DEVICE; + } + + if (cmd_limit_time_walk(p_ptr)) return; + + /* Roll for usage */ + if ((chance < USE_DEVICE) || (randint1(chance) < USE_DEVICE) || (p_ptr->pclass == CLASS_BERSERKER)) + { + if (flush_failure) flush(); + msg_print(_("杖をうまく使えなかった。", "You failed to use the staff properly.")); + sound(SOUND_FAIL); + return; + } + + /* Notice empty staffs */ + if (o_ptr->pval <= 0) + { + if (flush_failure) flush(); + msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left.")); + o_ptr->ident |= (IDENT_EMPTY); + p_ptr->update |= (PU_COMBINE | PU_REORDER); + p_ptr->window |= (PW_INVEN); + + return; + } + + + sound(SOUND_ZAP); + + ident = staff_effect(o_ptr->sval, &use_charge, FALSE, FALSE, object_is_aware(o_ptr)); + + if (!(object_is_aware(o_ptr))) + { + chg_virtue(V_PATIENCE, -1); + chg_virtue(V_CHANCE, 1); + chg_virtue(V_KNOWLEDGE, -1); + } + p_ptr->update |= (PU_COMBINE | PU_REORDER); + + /* Tried the item */ + object_tried(o_ptr); + + /* An identification was made */ + if (ident && !object_is_aware(o_ptr)) + { + object_aware(o_ptr); + gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); + } + + p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); + + + /* Hack -- some uses are "free" */ + if (!use_charge) return; + + + /* Use a single charge */ + o_ptr->pval--; + + /* XXX Hack -- unstack if necessary */ + if ((item >= 0) && (o_ptr->number > 1)) + { + object_type forge; + object_type *q_ptr; + q_ptr = &forge; + + /* Obtain a local object */ + object_copy(q_ptr, o_ptr); + + /* Modify quantity */ + q_ptr->number = 1; + + /* Restore the charges */ + o_ptr->pval++; + + /* Unstack the used item */ + o_ptr->number--; + p_ptr->total_weight -= q_ptr->weight; + item = inven_carry(q_ptr); + + msg_print(_("杖をまとめなおした。", "You unstack your staff.")); + } + + /* Describe charges in the pack */ + if (item >= 0) + { + inven_item_charges(item); + } + + /* Describe charges on the floor */ + else + { + floor_item_charges(0 - item); + } +} + +/*! +* @brief 杖を使うコマンドのメインルーチン / +* @return なし +*/ +void do_cmd_use_staff(void) +{ + OBJECT_IDX item; + concptr q, s; + + if (p_ptr->wild_mode) + { + return; + } + + if (cmd_limit_arena(p_ptr)) return; + + if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) + { + set_action(ACTION_NONE); + } + + /* Restrict choices to wands */ + item_tester_tval = TV_STAFF; + + q = _("どの杖を使いますか? ", "Use which staff? "); + s = _("使える杖がない。", "You have no staff to use."); + + if (!choose_object(&item, q, s, (USE_INVEN | USE_FLOOR))) return; + + do_cmd_use_staff_aux(item); +} diff --git a/src/cmd-usestaff.h b/src/cmd-usestaff.h index 3efd914b0..79bf8bfd0 100644 --- a/src/cmd-usestaff.h +++ b/src/cmd-usestaff.h @@ -1,3 +1,3 @@ -extern int staff_effect(OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known); -extern void do_cmd_use_staff_aux(INVENTORY_IDX item); -extern void do_cmd_use_staff(void); +extern int staff_effect(OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known); +extern void do_cmd_use_staff_aux(INVENTORY_IDX item); +extern void do_cmd_use_staff(void); diff --git a/src/floor-events.c b/src/floor-events.c index 3eddb676e..02f4db490 100644 --- a/src/floor-events.c +++ b/src/floor-events.c @@ -1,115 +1,115 @@ -#include "angband.h" - -void day_break() -{ - POSITION y, x; - msg_print(_("夜が明けた。", "The sun has risen.")); - - if (!p_ptr->wild_mode) - { - /* Hack -- Scan the town */ - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - /* Get the cave grid */ - cave_type *c_ptr = &cave[y][x]; - - /* Assume lit */ - c_ptr->info |= (CAVE_GLOW); - - /* Hack -- Memorize lit grids if allowed */ - if (view_perma_grids) c_ptr->info |= (CAVE_MARK); - - /* Hack -- Notice spot */ - note_spot(y, x); - } - } - } - - p_ptr->update |= (PU_MONSTERS | PU_MON_LITE); - p_ptr->redraw |= (PR_MAP); - p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); - - if (p_ptr->special_defense & NINJA_S_STEALTH) - { - if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); - } - -} - -void night_falls(void) -{ - POSITION y, x; - msg_print(_("日が沈んだ。", "The sun has fallen.")); - - if (!p_ptr->wild_mode) - { - /* Hack -- Scan the town */ - for (y = 0; y < cur_hgt; y++) - { - for (x = 0; x < cur_wid; x++) - { - /* Get the cave grid */ - cave_type *c_ptr = &cave[y][x]; - - /* Feature code (applying "mimic" field) */ - feature_type *f_ptr = &f_info[get_feat_mimic(c_ptr)]; - - if (!is_mirror_grid(c_ptr) && !have_flag(f_ptr->flags, FF_QUEST_ENTER) && - !have_flag(f_ptr->flags, FF_ENTRANCE)) - { - /* Assume dark */ - c_ptr->info &= ~(CAVE_GLOW); - - if (!have_flag(f_ptr->flags, FF_REMEMBER)) - { - /* Forget the normal floor grid */ - c_ptr->info &= ~(CAVE_MARK); - - /* Hack -- Notice spot */ - note_spot(y, x); - } - } - } - - /* Glow deep lava and building entrances */ - glow_deep_lava_and_bldg(); - } - } - - p_ptr->update |= (PU_MONSTERS | PU_MON_LITE); - p_ptr->redraw |= (PR_MAP); - p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); - - if (p_ptr->special_defense & NINJA_S_STEALTH) - { - if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); - } - -} - -/*! - * @brief 現在フロアに残っている敵モンスターの数を返す / - * @return 現在の敵モンスターの数 - */ -MONSTER_NUMBER count_all_hostile_monsters(void) -{ - POSITION x, y; - MONSTER_NUMBER number_mon = 0; - - for (x = 0; x < cur_wid; ++x) - { - for (y = 0; y < cur_hgt; ++y) - { - MONSTER_IDX m_idx = cave[y][x].m_idx; - - if (m_idx > 0 && is_hostile(&m_list[m_idx])) - { - ++number_mon; - } - } - } - - return number_mon; -} +#include "angband.h" + +void day_break() +{ + POSITION y, x; + msg_print(_("夜が明けた。", "The sun has risen.")); + + if (!p_ptr->wild_mode) + { + /* Hack -- Scan the town */ + for (y = 0; y < cur_hgt; y++) + { + for (x = 0; x < cur_wid; x++) + { + /* Get the cave grid */ + cave_type *c_ptr = &cave[y][x]; + + /* Assume lit */ + c_ptr->info |= (CAVE_GLOW); + + /* Hack -- Memorize lit grids if allowed */ + if (view_perma_grids) c_ptr->info |= (CAVE_MARK); + + /* Hack -- Notice spot */ + note_spot(y, x); + } + } + } + + p_ptr->update |= (PU_MONSTERS | PU_MON_LITE); + p_ptr->redraw |= (PR_MAP); + p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); + + if (p_ptr->special_defense & NINJA_S_STEALTH) + { + if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); + } + +} + +void night_falls(void) +{ + POSITION y, x; + msg_print(_("日が沈んだ。", "The sun has fallen.")); + + if (!p_ptr->wild_mode) + { + /* Hack -- Scan the town */ + for (y = 0; y < cur_hgt; y++) + { + for (x = 0; x < cur_wid; x++) + { + /* Get the cave grid */ + cave_type *c_ptr = &cave[y][x]; + + /* Feature code (applying "mimic" field) */ + feature_type *f_ptr = &f_info[get_feat_mimic(c_ptr)]; + + if (!is_mirror_grid(c_ptr) && !have_flag(f_ptr->flags, FF_QUEST_ENTER) && + !have_flag(f_ptr->flags, FF_ENTRANCE)) + { + /* Assume dark */ + c_ptr->info &= ~(CAVE_GLOW); + + if (!have_flag(f_ptr->flags, FF_REMEMBER)) + { + /* Forget the normal floor grid */ + c_ptr->info &= ~(CAVE_MARK); + + /* Hack -- Notice spot */ + note_spot(y, x); + } + } + } + + /* Glow deep lava and building entrances */ + glow_deep_lava_and_bldg(); + } + } + + p_ptr->update |= (PU_MONSTERS | PU_MON_LITE); + p_ptr->redraw |= (PR_MAP); + p_ptr->window |= (PW_OVERHEAD | PW_DUNGEON); + + if (p_ptr->special_defense & NINJA_S_STEALTH) + { + if (cave[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE); + } + +} + +/*! + * @brief 現在フロアに残っている敵モンスターの数を返す / + * @return 現在の敵モンスターの数 + */ +MONSTER_NUMBER count_all_hostile_monsters(void) +{ + POSITION x, y; + MONSTER_NUMBER number_mon = 0; + + for (x = 0; x < cur_wid; ++x) + { + for (y = 0; y < cur_hgt; ++y) + { + MONSTER_IDX m_idx = cave[y][x].m_idx; + + if (m_idx > 0 && is_hostile(&m_list[m_idx])) + { + ++number_mon; + } + } + } + + return number_mon; +} diff --git a/src/floor-events.h b/src/floor-events.h index 1b28acf75..fc70f7768 100644 --- a/src/floor-events.h +++ b/src/floor-events.h @@ -1,3 +1,3 @@ -void day_break(void); -void night_falls(void); -MONSTER_NUMBER count_all_hostile_monsters(void); +void day_break(void); +void night_falls(void); +MONSTER_NUMBER count_all_hostile_monsters(void); diff --git a/src/gameoption.h b/src/gameoption.h index ed3b07928..eae734ba5 100644 --- a/src/gameoption.h +++ b/src/gameoption.h @@ -1,170 +1,170 @@ -/*** Input Options ***/ - -extern bool rogue_like_commands; /* Rogue-like commands */ -extern bool always_pickup; /* Pick things up by default */ -extern bool carry_query_flag; /* Prompt before picking things up */ -extern bool quick_messages; /* Activate quick messages */ -extern bool auto_more; /* Automatically clear '-more-' prompts */ -extern bool command_menu; /* Enable command selection menu */ -extern bool other_query_flag; /* Prompt for floor item selection */ -extern bool use_old_target; /* Use old target by default */ -extern bool always_repeat; /* Repeat obvious commands */ -extern bool confirm_destroy; /* Prompt for destruction of known worthless items */ -extern bool confirm_wear; /* Confirm to wear/wield known cursed items */ -extern bool confirm_quest; /* Prompt before exiting a quest level */ -extern bool target_pet; /* Allow targetting pets */ -extern bool easy_open; /* Automatically open doors */ -extern bool easy_disarm; /* Automatically disarm traps */ -extern bool easy_floor; /* Display floor stacks in a list */ -extern bool use_command; /* Allow unified use command */ -extern bool over_exert; /* Allow casting spells when short of mana */ -extern bool numpad_as_cursorkey; /* Use numpad keys as cursor key in editor mode */ - - - /*** Map Screen Options ***/ - -extern bool center_player; /* Center map while walking (*slow*) */ -extern bool center_running; /* Centering even while running */ -extern bool view_yellow_lite; /* Use special colors for torch-lit grids */ -extern bool view_bright_lite; /* Use special colors for 'viewable' grids */ -extern bool view_granite_lite; /* Use special colors for wall grids (slow) */ -extern bool view_special_lite; /* Use special colors for floor grids (slow) */ -extern bool view_perma_grids; /* Map remembers all perma-lit grids */ -extern bool view_torch_grids; /* Map remembers all torch-lit grids */ -extern bool view_unsafe_grids; /* Map marked by detect traps */ -extern bool view_reduce_view; /* Reduce view-radius in town */ -extern bool fresh_before; /* Flush output while continuous command */ -extern bool fresh_after; /* Flush output after monster's move */ -extern bool fresh_message; /* Flush output after every message */ -extern bool hilite_player; /* Hilite the player with the cursor */ -extern bool display_path; /* Display actual path before shooting */ - - - /*** Text Display Options ***/ - -extern bool plain_descriptions; /* Plain object descriptions */ -extern bool plain_pickup; /* Plain pickup messages(japanese only) */ -extern bool always_show_list; /* Always show list when choosing items */ -extern bool depth_in_feet; /* Show dungeon level in feet */ -extern bool show_labels; /* Show labels in object listings */ -extern bool show_weights; /* Show weights in object listings */ -extern bool show_item_graph; /* Show items graphics */ -extern bool equippy_chars; /* Display 'equippy' chars */ -extern bool display_mutations; /* Display mutations in 'C'haracter Display */ -extern bool compress_savefile; /* Compress messages in savefiles */ -extern bool abbrev_extra; /* Describe obj's extra resistances by abbreviation */ -extern bool abbrev_all; /* Describe obj's all resistances by abbreviation */ -extern bool exp_need; /* Show the experience needed for next level */ -extern bool ignore_unview; /* Ignore whenever any monster does */ -extern bool show_ammo_detail; /* Show Description of ammo damage */ -extern bool show_ammo_no_crit; /* Show No-crit damage of ammo */ -extern bool show_ammo_crit_ratio; /* Show critical ratio of ammo */ -extern bool show_actual_value; /* Show actual value of skill */ - - /*** Game-Play Options ***/ - -extern bool stack_force_notes; /* Merge inscriptions when stacking */ -extern bool stack_force_costs; /* Merge discounts when stacking */ -extern bool expand_list; /* Expand the power of the list commands */ -extern bool small_levels; /* Allow unusually small dungeon levels */ -extern bool always_small_levels; /* Always create unusually small dungeon levels */ -extern bool empty_levels; /* Allow empty 'arena' levels */ -extern bool bound_walls_perm; /* Boundary walls become 'permanent wall' */ -extern bool last_words; /* Leave last words when your character dies */ - -#ifdef WORLD_SCORE -extern bool send_score; /* Send score dump to the world score server */ -#endif - -extern bool allow_debug_opts; /* Allow use of debug/cheat options */ - - - /*** Disturbance Options ***/ - -extern bool find_ignore_stairs; /* Run past stairs */ -extern bool find_ignore_doors; /* Run through open doors */ -extern bool find_cut; /* Run past known corners */ -extern bool check_abort; /* Check for user abort while continuous command */ -extern bool flush_failure; /* Flush input on various failures */ -extern bool flush_disturb; /* Flush input whenever disturbed */ -extern bool disturb_move; /* Disturb whenever any monster moves */ -extern bool disturb_high; /* Disturb whenever high-level monster moves */ -extern bool disturb_near; /* Disturb whenever viewable monster moves */ -extern bool disturb_pets; /* Disturb when visible pets move */ -extern bool disturb_panel; /* Disturb whenever map panel changes */ -extern bool disturb_state; /* Disturb whenever player state changes */ -extern bool disturb_minor; /* Disturb whenever boring things happen */ -extern bool ring_bell; /* Audible bell (on errors, etc) */ -extern bool disturb_trap_detect; /* Disturb when leaving trap detected area */ -extern bool alert_trap_detect; /* Alert when leaving trap detected area */ - - - /*** Birth Options ***/ - -extern bool manual_haggle; /* Manually haggle in stores */ -extern bool easy_band; /* Easy Mode (*) */ -extern bool smart_learn; /* Monsters learn from their mistakes (*) */ -extern bool smart_cheat; /* Monsters exploit players weaknesses (*) */ -extern bool vanilla_town; /* Use 'vanilla' town without quests and wilderness */ -extern bool lite_town; /* Use 'lite' town without a wilderness */ -extern bool ironman_shops; /* Stores are permanently closed (*) */ -extern bool ironman_small_levels; /* Always create unusually small dungeon levels (*) */ -extern bool ironman_downward; /* Disable recall and use of up stairs (*) */ -extern bool ironman_empty_levels; /* Always create empty 'arena' levels (*) */ -extern bool ironman_rooms; /* Always generate very unusual rooms (*) */ -extern bool ironman_nightmare; /* Nightmare mode(it isn't even remotely fair!)(*) */ -extern bool left_hander; /* Left-Hander */ -extern bool preserve_mode; /* Preserve artifacts (*) */ -extern bool autoroller; /* Allow use of autoroller for stats (*) */ -extern bool autochara; /* Autoroll for weight, height and social status */ -extern bool powerup_home; /* Increase capacity of your home (*) */ - - - /*** Easy Object Auto-Destroyer ***/ - -extern bool destroy_items; /* Use easy auto-destroyer */ -extern bool destroy_feeling; /* Apply auto-destroy as sense feeling */ -extern bool destroy_identify; /* Apply auto-destroy as identify an item */ -extern bool leave_worth; /* Auto-destroyer leaves known worthy items */ -extern bool leave_equip; /* Auto-destroyer leaves weapons and armour */ -extern bool leave_chest; /* Auto-destroyer leaves closed chests */ -extern bool leave_wanted; /* Auto-destroyer leaves wanted corpses */ -extern bool leave_corpse; /* Auto-destroyer leaves corpses and skeletons */ -extern bool leave_junk; /* Auto-destroyer leaves junk */ -extern bool leave_special; /* Auto-destroyer leaves items your race/class needs */ - - - /*** Play-record Options ***/ - -extern bool record_fix_art; /* Record fixed artifacts */ -extern bool record_rand_art; /* Record random artifacts */ -extern bool record_destroy_uniq; /* Record when destroy unique monster */ -extern bool record_fix_quest; /* Record fixed quests */ -extern bool record_rand_quest; /* Record random quests */ -extern bool record_maxdepth; /* Record movements to deepest level */ -extern bool record_stair; /* Record recall and stair movements */ -extern bool record_buy; /* Record purchased items */ -extern bool record_sell; /* Record sold items */ -extern bool record_danger; /* Record hitpoint warning */ -extern bool record_arena; /* Record arena victories */ -extern bool record_ident; /* Record first identified items */ -extern bool record_named_pet; /* Record informations of named pets */ - - -extern bool cheat_peek; -extern bool cheat_hear; -extern bool cheat_room; -extern bool cheat_xtra; -extern bool cheat_know; -extern bool cheat_live; -extern bool cheat_save; -extern bool cheat_diary_output; -extern bool cheat_turn; -extern bool cheat_sight; - -extern byte hitpoint_warn; -extern byte mana_warn; -extern byte delay_factor; -extern s16b autosave_freq; -extern bool autosave_t; -extern bool autosave_l; +/*** Input Options ***/ + +extern bool rogue_like_commands; /* Rogue-like commands */ +extern bool always_pickup; /* Pick things up by default */ +extern bool carry_query_flag; /* Prompt before picking things up */ +extern bool quick_messages; /* Activate quick messages */ +extern bool auto_more; /* Automatically clear '-more-' prompts */ +extern bool command_menu; /* Enable command selection menu */ +extern bool other_query_flag; /* Prompt for floor item selection */ +extern bool use_old_target; /* Use old target by default */ +extern bool always_repeat; /* Repeat obvious commands */ +extern bool confirm_destroy; /* Prompt for destruction of known worthless items */ +extern bool confirm_wear; /* Confirm to wear/wield known cursed items */ +extern bool confirm_quest; /* Prompt before exiting a quest level */ +extern bool target_pet; /* Allow targetting pets */ +extern bool easy_open; /* Automatically open doors */ +extern bool easy_disarm; /* Automatically disarm traps */ +extern bool easy_floor; /* Display floor stacks in a list */ +extern bool use_command; /* Allow unified use command */ +extern bool over_exert; /* Allow casting spells when short of mana */ +extern bool numpad_as_cursorkey; /* Use numpad keys as cursor key in editor mode */ + + + /*** Map Screen Options ***/ + +extern bool center_player; /* Center map while walking (*slow*) */ +extern bool center_running; /* Centering even while running */ +extern bool view_yellow_lite; /* Use special colors for torch-lit grids */ +extern bool view_bright_lite; /* Use special colors for 'viewable' grids */ +extern bool view_granite_lite; /* Use special colors for wall grids (slow) */ +extern bool view_special_lite; /* Use special colors for floor grids (slow) */ +extern bool view_perma_grids; /* Map remembers all perma-lit grids */ +extern bool view_torch_grids; /* Map remembers all torch-lit grids */ +extern bool view_unsafe_grids; /* Map marked by detect traps */ +extern bool view_reduce_view; /* Reduce view-radius in town */ +extern bool fresh_before; /* Flush output while continuous command */ +extern bool fresh_after; /* Flush output after monster's move */ +extern bool fresh_message; /* Flush output after every message */ +extern bool hilite_player; /* Hilite the player with the cursor */ +extern bool display_path; /* Display actual path before shooting */ + + + /*** Text Display Options ***/ + +extern bool plain_descriptions; /* Plain object descriptions */ +extern bool plain_pickup; /* Plain pickup messages(japanese only) */ +extern bool always_show_list; /* Always show list when choosing items */ +extern bool depth_in_feet; /* Show dungeon level in feet */ +extern bool show_labels; /* Show labels in object listings */ +extern bool show_weights; /* Show weights in object listings */ +extern bool show_item_graph; /* Show items graphics */ +extern bool equippy_chars; /* Display 'equippy' chars */ +extern bool display_mutations; /* Display mutations in 'C'haracter Display */ +extern bool compress_savefile; /* Compress messages in savefiles */ +extern bool abbrev_extra; /* Describe obj's extra resistances by abbreviation */ +extern bool abbrev_all; /* Describe obj's all resistances by abbreviation */ +extern bool exp_need; /* Show the experience needed for next level */ +extern bool ignore_unview; /* Ignore whenever any monster does */ +extern bool show_ammo_detail; /* Show Description of ammo damage */ +extern bool show_ammo_no_crit; /* Show No-crit damage of ammo */ +extern bool show_ammo_crit_ratio; /* Show critical ratio of ammo */ +extern bool show_actual_value; /* Show actual value of skill */ + + /*** Game-Play Options ***/ + +extern bool stack_force_notes; /* Merge inscriptions when stacking */ +extern bool stack_force_costs; /* Merge discounts when stacking */ +extern bool expand_list; /* Expand the power of the list commands */ +extern bool small_levels; /* Allow unusually small dungeon levels */ +extern bool always_small_levels; /* Always create unusually small dungeon levels */ +extern bool empty_levels; /* Allow empty 'arena' levels */ +extern bool bound_walls_perm; /* Boundary walls become 'permanent wall' */ +extern bool last_words; /* Leave last words when your character dies */ + +#ifdef WORLD_SCORE +extern bool send_score; /* Send score dump to the world score server */ +#endif + +extern bool allow_debug_opts; /* Allow use of debug/cheat options */ + + + /*** Disturbance Options ***/ + +extern bool find_ignore_stairs; /* Run past stairs */ +extern bool find_ignore_doors; /* Run through open doors */ +extern bool find_cut; /* Run past known corners */ +extern bool check_abort; /* Check for user abort while continuous command */ +extern bool flush_failure; /* Flush input on various failures */ +extern bool flush_disturb; /* Flush input whenever disturbed */ +extern bool disturb_move; /* Disturb whenever any monster moves */ +extern bool disturb_high; /* Disturb whenever high-level monster moves */ +extern bool disturb_near; /* Disturb whenever viewable monster moves */ +extern bool disturb_pets; /* Disturb when visible pets move */ +extern bool disturb_panel; /* Disturb whenever map panel changes */ +extern bool disturb_state; /* Disturb whenever player state changes */ +extern bool disturb_minor; /* Disturb whenever boring things happen */ +extern bool ring_bell; /* Audible bell (on errors, etc) */ +extern bool disturb_trap_detect; /* Disturb when leaving trap detected area */ +extern bool alert_trap_detect; /* Alert when leaving trap detected area */ + + + /*** Birth Options ***/ + +extern bool manual_haggle; /* Manually haggle in stores */ +extern bool easy_band; /* Easy Mode (*) */ +extern bool smart_learn; /* Monsters learn from their mistakes (*) */ +extern bool smart_cheat; /* Monsters exploit players weaknesses (*) */ +extern bool vanilla_town; /* Use 'vanilla' town without quests and wilderness */ +extern bool lite_town; /* Use 'lite' town without a wilderness */ +extern bool ironman_shops; /* Stores are permanently closed (*) */ +extern bool ironman_small_levels; /* Always create unusually small dungeon levels (*) */ +extern bool ironman_downward; /* Disable recall and use of up stairs (*) */ +extern bool ironman_empty_levels; /* Always create empty 'arena' levels (*) */ +extern bool ironman_rooms; /* Always generate very unusual rooms (*) */ +extern bool ironman_nightmare; /* Nightmare mode(it isn't even remotely fair!)(*) */ +extern bool left_hander; /* Left-Hander */ +extern bool preserve_mode; /* Preserve artifacts (*) */ +extern bool autoroller; /* Allow use of autoroller for stats (*) */ +extern bool autochara; /* Autoroll for weight, height and social status */ +extern bool powerup_home; /* Increase capacity of your home (*) */ + + + /*** Easy Object Auto-Destroyer ***/ + +extern bool destroy_items; /* Use easy auto-destroyer */ +extern bool destroy_feeling; /* Apply auto-destroy as sense feeling */ +extern bool destroy_identify; /* Apply auto-destroy as identify an item */ +extern bool leave_worth; /* Auto-destroyer leaves known worthy items */ +extern bool leave_equip; /* Auto-destroyer leaves weapons and armour */ +extern bool leave_chest; /* Auto-destroyer leaves closed chests */ +extern bool leave_wanted; /* Auto-destroyer leaves wanted corpses */ +extern bool leave_corpse; /* Auto-destroyer leaves corpses and skeletons */ +extern bool leave_junk; /* Auto-destroyer leaves junk */ +extern bool leave_special; /* Auto-destroyer leaves items your race/class needs */ + + + /*** Play-record Options ***/ + +extern bool record_fix_art; /* Record fixed artifacts */ +extern bool record_rand_art; /* Record random artifacts */ +extern bool record_destroy_uniq; /* Record when destroy unique monster */ +extern bool record_fix_quest; /* Record fixed quests */ +extern bool record_rand_quest; /* Record random quests */ +extern bool record_maxdepth; /* Record movements to deepest level */ +extern bool record_stair; /* Record recall and stair movements */ +extern bool record_buy; /* Record purchased items */ +extern bool record_sell; /* Record sold items */ +extern bool record_danger; /* Record hitpoint warning */ +extern bool record_arena; /* Record arena victories */ +extern bool record_ident; /* Record first identified items */ +extern bool record_named_pet; /* Record informations of named pets */ + + +extern bool cheat_peek; +extern bool cheat_hear; +extern bool cheat_room; +extern bool cheat_xtra; +extern bool cheat_know; +extern bool cheat_live; +extern bool cheat_save; +extern bool cheat_diary_output; +extern bool cheat_turn; +extern bool cheat_sight; + +extern byte hitpoint_warn; +extern byte mana_warn; +extern byte delay_factor; +extern s16b autosave_freq; +extern bool autosave_t; +extern bool autosave_l; diff --git a/src/gamevalue.h b/src/gamevalue.h index f8517c382..e451f9932 100644 --- a/src/gamevalue.h +++ b/src/gamevalue.h @@ -1,133 +1,133 @@ - -/*! -* @brief ベースアイテム生成階層が加算される確率 -* @details -* There is a 1/10 (10%) chance of inflating the requested object_level -* during the creation of an object (see "get_obj_num()" in "object.c"). -* Lower values yield better objects more often. -*/ -#define GREAT_OBJ 10 - -/*! -* @brief 深層モンスターが生成される(NASTY生成)の基本確率(1/x) -* @details -* There is a 1/25 (4%) chance of inflating the requested monster_level -* during the creation of a monsters (see "get_mon_num()" in "monster.c"). -* Lower values yield harder monsters more often. -*/ -#define NASTY_MON_BASE 25 -#define NASTY_MON_MAX 3 /*!< 深層モンスターが1フロアに生成される最大数 */ -#define NASTY_MON_PLUS_MAX 25 /*!< 深層モンスターの階層加算最大量 */ - -#define PENETRATE_INVULNERABILITY 13 /*!< 無敵化が破られる確率(1/x) / 1/x chance of hurting even if invulnerable! */ - -#define MAX_TELEPORT_DISTANCE 200 /*!< テレポート最大距離 */ - -/* -* Refueling constants -*/ -#define FUEL_TORCH 5000 /*!< 松明の基本寿命値 / Maximum amount of fuel in a torch */ -#define FUEL_LAMP 15000 /*!< ランタンの基本寿命値 / Maximum amount of fuel in a lantern */ - -/* -* More maximum values -*/ -#define MAX_SIGHT 20 /*!< プレイヤーの最大視界範囲(マス) / Maximum view distance */ -#define MAX_RANGE (p_ptr->inside_battle ? 36 : 18) /*!< プレイヤーの攻撃射程(マス) / Maximum range (spells, etc) */ -#define AAF_LIMIT 100 /*!< モンスターの限界感知範囲(マス) Limit of sensing radius */ - -#define MIN_M_ALLOC_TD 4 /*!< 街(昼間)の最低住人配置数 / The town starts out with 4 residents during the day */ -#define MIN_M_ALLOC_TN 8 /*!< 街(夜間)の最低住人配置数 / The town starts out with 8 residents during the night */ - -/*! -* @brief モンスター増殖の最大数 -* @details -* A monster can only "multiply" (reproduce) if there are fewer than 100 -* monsters on the level capable of such spontaneous reproduction. This -* is a hack which prevents the "m_list[]" array from exploding due to -* reproducing monsters. Messy, but necessary. -*/ -#define MAX_REPRO 100 - -#define MAX_VAMPIRIC_DRAIN 50 /*!< 吸血処理の最大回復HP */ - -/* -* Dungeon generation values -*/ -#define DUN_UNUSUAL 250 /*!< 通常ではない部屋が生成される基本確率(レベル/定数) / Level/chance of unusual room (was 200) */ -#define DUN_DEST 18 /*!< 破壊地形がフロアに発生する基本確率(1/定数) / 1/chance of having a destroyed level */ -#define SMALL_LEVEL 3 /*!< 小さいフロアの生成される基本確率(1/定数) / 1/chance of smaller size (3) */ -#define EMPTY_LEVEL 24 /*!< アリーナレベル(外壁のないフロア)の生成される基本確率(1/定数) / 1/chance of being 'empty' (15) */ -#define LAKE_LEVEL 24 /*!< 川や湖のあるフロアの生成される確率(1/定数) / 1/chance of being a lake on the level */ -#define DARK_EMPTY 5 /*!< フロア全体が暗い可能性の基本確率(1/定数) / 1/chance of arena level NOT being lit (2) */ -#define DUN_CAVERN 20 /*!< 洞窟状のダンジョンが生成される基本確率(1/定数) / 1/chance of having a cavern level */ - -/* - * Dungeon tunnel generation values - */ -#define DUN_TUN_RND_MIN 5 /* Chance of random direction (was 10) */ -#define DUN_TUN_RND_MAX 20 -#define DUN_TUN_CHG_MIN 20 /* Chance of changing direction (was 30) */ -#define DUN_TUN_CHG_MAX 60 -#define DUN_TUN_CON_MIN 10 /* Chance of extra tunneling (was 15) */ -#define DUN_TUN_CON_MAX 40 -#define DUN_TUN_PEN_MIN 30 /* Chance of doors at room entrances (was 25) */ -#define DUN_TUN_PEN_MAX 70 -#define DUN_TUN_JCT_MIN 60 /* Chance of doors at tunnel junctions (was 90) */ -#define DUN_TUN_JCT_MAX 90 - -/* - * Dungeon streamer generation values - */ -#define DUN_STR_DEN 5 /* Density of streamers */ -#define DUN_STR_RNG 5 /* Width of streamers */ -#define DUN_STR_MAG 6 /* Number of magma streamers */ -#define DUN_STR_MC 30 /* 1/chance of treasure per magma */ -#define DUN_STR_QUA 4 /* Number of quartz streamers */ -#define DUN_STR_QC 15 /* 1/chance of treasure per quartz */ -#define DUN_STR_WLW 1 /* Width of lava & water streamers -KMW- */ -#define DUN_STR_DWLW 8 /* Density of water & lava streams -KMW- */ - -#define DUN_MOS_DEN 2 /* Density of moss streamers */ -#define DUN_MOS_RNG 10 /* Width of moss streamers */ -#define DUN_STR_MOS 2 /* Number of moss streamers */ -#define DUN_WAT_DEN 15 /* Density of rivers */ -#define DUN_WAT_RNG 2 /* Width of rivers */ -#define DUN_STR_WAT 3 /* Max number of rivers */ -#define DUN_WAT_CHG 50 /* 1 in 50 chance of junction in river */ - -/* - * Dungeon treausre allocation values - */ -#define DUN_AMT_ROOM 9 /* Amount of objects for rooms */ -#define DUN_AMT_ITEM 3 /* Amount of objects for rooms/corridors */ -#define DUN_AMT_GOLD 3 /* Amount of treasure for rooms/corridors */ -#define DUN_AMT_INVIS 3 /* Amount of invisible walls for rooms/corridors */ - - /* Chance of using syllables to form the name instead of the "template" files */ -#define SINDARIN_NAME 10 /*!< ランダムアーティファクトにシンダリン銘をつける確率 */ -#define TABLE_NAME 20 /*!< ランダムアーティファクトに漢字銘をつける確率(正確には TABLE_NAME - SINDARIN_NAME %)となる */ -#define A_CURSED 13 /*!< 1/nの確率で生成の巻物以外のランダムアーティファクトが呪いつきになる。 */ -#define WEIRD_LUCK 12 /*!< 1/nの確率でrandom_resistance()の処理中バイアス外の耐性がつき、create_artifactで4を超えるpvalが許可される。*/ -#define SWORDFISH_LUCK 6 /*!< 1/nの確率で一定以上のスレイダメージを超える武器のスレイ喪失が回避される。 */ -#define BIAS_LUCK 20 /*!< 1/nの確率でrandom_resistance()で付加する元素耐性が免疫になる */ -#define IM_LUCK 7 /*!< 1/nの確率でrandom_resistance()で複数免疫の除去処理が免除される */ - - /*! @note - * Bias luck needs to be higher than weird luck, - * since it is usually tested several times... - */ - -#define ACTIVATION_CHANCE 3 /*!< 1/nの確率でランダムアーティファクトに発動が付加される。ただし防具はさらに1/2 */ - -#define TY_CURSE_CHANCE 200 /*!<太古の怨念の1ターン毎の発動確率(1/n)*/ -#define CHAINSWORD_NOISE 100 /*!<チェンソーの1ターン毎の発動確率(1/n)*/ - -#define SPEAK_CHANCE 8 -#define GRINDNOISE 20 -#define CYBERNOISE 20 - -#define GROUP_MAX 32 /*!< place_monster_group() 関数によるモンスターのGROUP生成時の配置最大数 / Maximum size of a group of monsters */ - - /* ToDo: Make this global */ -#define HURT_CHANCE 16 /*!< 属性攻撃を受けた際に能力値低下を起こす確率(1/X) / 1/x chance of reducing stats (for elemental attacks) */ + +/*! +* @brief ベースアイテム生成階層が加算される確率 +* @details +* There is a 1/10 (10%) chance of inflating the requested object_level +* during the creation of an object (see "get_obj_num()" in "object.c"). +* Lower values yield better objects more often. +*/ +#define GREAT_OBJ 10 + +/*! +* @brief 深層モンスターが生成される(NASTY生成)の基本確率(1/x) +* @details +* There is a 1/25 (4%) chance of inflating the requested monster_level +* during the creation of a monsters (see "get_mon_num()" in "monster.c"). +* Lower values yield harder monsters more often. +*/ +#define NASTY_MON_BASE 25 +#define NASTY_MON_MAX 3 /*!< 深層モンスターが1フロアに生成される最大数 */ +#define NASTY_MON_PLUS_MAX 25 /*!< 深層モンスターの階層加算最大量 */ + +#define PENETRATE_INVULNERABILITY 13 /*!< 無敵化が破られる確率(1/x) / 1/x chance of hurting even if invulnerable! */ + +#define MAX_TELEPORT_DISTANCE 200 /*!< テレポート最大距離 */ + +/* +* Refueling constants +*/ +#define FUEL_TORCH 5000 /*!< 松明の基本寿命値 / Maximum amount of fuel in a torch */ +#define FUEL_LAMP 15000 /*!< ランタンの基本寿命値 / Maximum amount of fuel in a lantern */ + +/* +* More maximum values +*/ +#define MAX_SIGHT 20 /*!< プレイヤーの最大視界範囲(マス) / Maximum view distance */ +#define MAX_RANGE (p_ptr->inside_battle ? 36 : 18) /*!< プレイヤーの攻撃射程(マス) / Maximum range (spells, etc) */ +#define AAF_LIMIT 100 /*!< モンスターの限界感知範囲(マス) Limit of sensing radius */ + +#define MIN_M_ALLOC_TD 4 /*!< 街(昼間)の最低住人配置数 / The town starts out with 4 residents during the day */ +#define MIN_M_ALLOC_TN 8 /*!< 街(夜間)の最低住人配置数 / The town starts out with 8 residents during the night */ + +/*! +* @brief モンスター増殖の最大数 +* @details +* A monster can only "multiply" (reproduce) if there are fewer than 100 +* monsters on the level capable of such spontaneous reproduction. This +* is a hack which prevents the "m_list[]" array from exploding due to +* reproducing monsters. Messy, but necessary. +*/ +#define MAX_REPRO 100 + +#define MAX_VAMPIRIC_DRAIN 50 /*!< 吸血処理の最大回復HP */ + +/* +* Dungeon generation values +*/ +#define DUN_UNUSUAL 250 /*!< 通常ではない部屋が生成される基本確率(レベル/定数) / Level/chance of unusual room (was 200) */ +#define DUN_DEST 18 /*!< 破壊地形がフロアに発生する基本確率(1/定数) / 1/chance of having a destroyed level */ +#define SMALL_LEVEL 3 /*!< 小さいフロアの生成される基本確率(1/定数) / 1/chance of smaller size (3) */ +#define EMPTY_LEVEL 24 /*!< アリーナレベル(外壁のないフロア)の生成される基本確率(1/定数) / 1/chance of being 'empty' (15) */ +#define LAKE_LEVEL 24 /*!< 川や湖のあるフロアの生成される確率(1/定数) / 1/chance of being a lake on the level */ +#define DARK_EMPTY 5 /*!< フロア全体が暗い可能性の基本確率(1/定数) / 1/chance of arena level NOT being lit (2) */ +#define DUN_CAVERN 20 /*!< 洞窟状のダンジョンが生成される基本確率(1/定数) / 1/chance of having a cavern level */ + +/* + * Dungeon tunnel generation values + */ +#define DUN_TUN_RND_MIN 5 /* Chance of random direction (was 10) */ +#define DUN_TUN_RND_MAX 20 +#define DUN_TUN_CHG_MIN 20 /* Chance of changing direction (was 30) */ +#define DUN_TUN_CHG_MAX 60 +#define DUN_TUN_CON_MIN 10 /* Chance of extra tunneling (was 15) */ +#define DUN_TUN_CON_MAX 40 +#define DUN_TUN_PEN_MIN 30 /* Chance of doors at room entrances (was 25) */ +#define DUN_TUN_PEN_MAX 70 +#define DUN_TUN_JCT_MIN 60 /* Chance of doors at tunnel junctions (was 90) */ +#define DUN_TUN_JCT_MAX 90 + +/* + * Dungeon streamer generation values + */ +#define DUN_STR_DEN 5 /* Density of streamers */ +#define DUN_STR_RNG 5 /* Width of streamers */ +#define DUN_STR_MAG 6 /* Number of magma streamers */ +#define DUN_STR_MC 30 /* 1/chance of treasure per magma */ +#define DUN_STR_QUA 4 /* Number of quartz streamers */ +#define DUN_STR_QC 15 /* 1/chance of treasure per quartz */ +#define DUN_STR_WLW 1 /* Width of lava & water streamers -KMW- */ +#define DUN_STR_DWLW 8 /* Density of water & lava streams -KMW- */ + +#define DUN_MOS_DEN 2 /* Density of moss streamers */ +#define DUN_MOS_RNG 10 /* Width of moss streamers */ +#define DUN_STR_MOS 2 /* Number of moss streamers */ +#define DUN_WAT_DEN 15 /* Density of rivers */ +#define DUN_WAT_RNG 2 /* Width of rivers */ +#define DUN_STR_WAT 3 /* Max number of rivers */ +#define DUN_WAT_CHG 50 /* 1 in 50 chance of junction in river */ + +/* + * Dungeon treausre allocation values + */ +#define DUN_AMT_ROOM 9 /* Amount of objects for rooms */ +#define DUN_AMT_ITEM 3 /* Amount of objects for rooms/corridors */ +#define DUN_AMT_GOLD 3 /* Amount of treasure for rooms/corridors */ +#define DUN_AMT_INVIS 3 /* Amount of invisible walls for rooms/corridors */ + + /* Chance of using syllables to form the name instead of the "template" files */ +#define SINDARIN_NAME 10 /*!< ランダムアーティファクトにシンダリン銘をつける確率 */ +#define TABLE_NAME 20 /*!< ランダムアーティファクトに漢字銘をつける確率(正確には TABLE_NAME - SINDARIN_NAME %)となる */ +#define A_CURSED 13 /*!< 1/nの確率で生成の巻物以外のランダムアーティファクトが呪いつきになる。 */ +#define WEIRD_LUCK 12 /*!< 1/nの確率でrandom_resistance()の処理中バイアス外の耐性がつき、create_artifactで4を超えるpvalが許可される。*/ +#define SWORDFISH_LUCK 6 /*!< 1/nの確率で一定以上のスレイダメージを超える武器のスレイ喪失が回避される。 */ +#define BIAS_LUCK 20 /*!< 1/nの確率でrandom_resistance()で付加する元素耐性が免疫になる */ +#define IM_LUCK 7 /*!< 1/nの確率でrandom_resistance()で複数免疫の除去処理が免除される */ + + /*! @note + * Bias luck needs to be higher than weird luck, + * since it is usually tested several times... + */ + +#define ACTIVATION_CHANCE 3 /*!< 1/nの確率でランダムアーティファクトに発動が付加される。ただし防具はさらに1/2 */ + +#define TY_CURSE_CHANCE 200 /*!<太古の怨念の1ターン毎の発動確率(1/n)*/ +#define CHAINSWORD_NOISE 100 /*!<チェンソーの1ターン毎の発動確率(1/n)*/ + +#define SPEAK_CHANCE 8 +#define GRINDNOISE 20 +#define CYBERNOISE 20 + +#define GROUP_MAX 32 /*!< place_monster_group() 関数によるモンスターのGROUP生成時の配置最大数 / Maximum size of a group of monsters */ + + /* ToDo: Make this global */ +#define HURT_CHANCE 16 /*!< 属性攻撃を受けた際に能力値低下を起こす確率(1/X) / 1/x chance of reducing stats (for elemental attacks) */ diff --git a/src/history.h b/src/history.h index 9518e4165..dcb64b0e6 100644 --- a/src/history.h +++ b/src/history.h @@ -1,21 +1,21 @@ - -/*! -* 生い立ちメッセージテーブル / Forward declare -*/ -typedef struct hist_type hist_type; - -/*! -* 生い立ちメッセージテーブルの構造体定義 / Player background information -*/ -struct hist_type -{ - concptr info; /*!> メッセージ本文 / Textual History */ - - byte roll; /*!> 確率の重み / Frequency of this entry */ - byte chart; /*!> 生い立ちメッセージの流れを示すチャートID / Chart index */ - byte next; /*!> 次のチャートID */ - byte bonus; /*!> メッセージに伴う社会的地位の変化量(50が基準値) / Social Class Bonus + 50 */ -}; - -struct hist_type; -extern hist_type bg[]; + +/*! +* 生い立ちメッセージテーブル / Forward declare +*/ +typedef struct hist_type hist_type; + +/*! +* 生い立ちメッセージテーブルの構造体定義 / Player background information +*/ +struct hist_type +{ + concptr info; /*!> メッセージ本文 / Textual History */ + + byte roll; /*!> 確率の重み / Frequency of this entry */ + byte chart; /*!> 生い立ちメッセージの流れを示すチャートID / Chart index */ + byte next; /*!> 次のチャートID */ + byte bonus; /*!> メッセージに伴う社会的地位の変化量(50が基準値) / Social Class Bonus + 50 */ +}; + +struct hist_type; +extern hist_type bg[]; diff --git a/src/main-win.c b/src/main-win.c index f56c787e3..a848e2a0a 100644 --- a/src/main-win.c +++ b/src/main-win.c @@ -1,5799 +1,5799 @@ -/*! -* @file main-win.c -* @brief Windows版固有実装(メインエントリポイント含む) -* @date 2018/03/16 -* @author Hengband Team -* @detail -* -*

概要

-* Windows98かその前後の頃を起点としたAPI実装。 -* 各種のゲームエンジンは無論、 -* DirectXといった昨今描画に標準的となったライブラリも用いていない。 -* タイルの描画処理などについては、現在動作の詳細を検証中。 -* -*

フォーク元の概要

-*

-* Copyright (c) 1997 Ben Harrison, Skirmantas Kligys, and others -* -* This software may be copied and distributed for educational, research, -* and not for profit purposes provided that this copyright and statement -* are included in all such copies. -*

-*

-* This file helps Angband work with Windows computers. -* -* To use this file, use an appropriate "Makefile" or "Project File", -* make sure that "WINDOWS" and/or "WIN32" are defined somewhere, and -* make sure to obtain various extra files as described below. -* -* The official compilation uses the CodeWarrior Pro compiler, which -* includes a special project file and precompilable header file. -*

-* -*

-* See also "main-dos.c" and "main-ibm.c". -*

-* -*

-* The "lib/user/pref-win.prf" file contains keymaps, macro definitions, -* and/or color redefinitions. -*

-* -*

-* The "lib/user/font-win.prf" contains attr/char mappings for use with the -* normal "lib/xtra/font/*.fon" font files. -*

-* -*

-* The "lib/user/graf-win.prf" contains attr/char mappings for use with the -* special "lib/xtra/graf/*.bmp" bitmap files, which are activated by a menu -* item. -*

-* -*

-* Compiling this file, and using the resulting executable, requires -* several extra files not distributed with the standard Angband code. -* If "USE_GRAPHICS" is defined, then "readdib.h" and "readdib.c" must -* be placed into "src/", and the "8X8.BMP" bitmap file must be placed -* into "lib/xtra/graf". In any case, some "*.fon" files (including -* "8X13.FON" if nothing else) must be placed into "lib/xtra/font/". -* If "USE_SOUND" is defined, then some special library (for example, -* "winmm.lib") may need to be linked in, and desired "*.WAV" sound -* files must be placed into "lib/xtra/sound/". All of these extra -* files can be found in the "ext-win" archive. -*

-* -*

-* The "Term_xtra_win_clear()" function should probably do a low-level -* clear of the current window, and redraw the borders and other things, -* if only for efficiency. -*

-* -*

-* A simpler method is needed for selecting the "tile size" for windows. -*

-* -*

-* The various "warning" messages assume the existance of the "screen.w" -* window, I think, and only a few calls actually check for its existance, -* this may be okay since "NULL" means "on top of all windows". (?) The -* user must never be allowed to "hide" the main window, or the "menubar" -* will disappear. -*

-* -*

-* Special "Windows Help Files" can be placed into "lib/xtra/help/" for -* use with the "winhelp.exe" program. These files *may* be available -* at the ftp site somewhere, but I have not seen them. -*

-* -*

-* Initial framework (and most code) by Ben Harrison (benh@phial.com). -* -* Original code by Skirmantas Kligys (kligys@scf.usc.edu). -* -* Additional code by Ross E Becker (beckerr@cis.ohio-state.edu), -* and Chris R. Martin (crm7479@tam2000.tamu.edu). -*

-*/ - -#include "angband.h" - -#ifdef WINDOWS -#include -#include -#include -#include "z-term.h" - -/* - * Extract the "WIN32" flag from the compiler - */ -#if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__) -# ifndef WIN32 -# define WIN32 -# endif -#endif - - -/* - * Hack -- allow use of "screen saver" mode - */ -#define USE_SAVER - - -/* - * Menu constants -- see "ANGBAND.RC" - */ - -#define IDM_FILE_NEW 100 -#define IDM_FILE_OPEN 101 -#define IDM_FILE_SAVE 110 -#define IDM_FILE_SCORE 120 -#define IDM_FILE_MOVIE 121 -#define IDM_FILE_EXIT 130 - -#define IDM_WINDOW_VIS_0 200 -#define IDM_WINDOW_VIS_1 201 -#define IDM_WINDOW_VIS_2 202 -#define IDM_WINDOW_VIS_3 203 -#define IDM_WINDOW_VIS_4 204 -#define IDM_WINDOW_VIS_5 205 -#define IDM_WINDOW_VIS_6 206 -#define IDM_WINDOW_VIS_7 207 - -#define IDM_WINDOW_FONT_0 210 -#define IDM_WINDOW_FONT_1 211 -#define IDM_WINDOW_FONT_2 212 -#define IDM_WINDOW_FONT_3 213 -#define IDM_WINDOW_FONT_4 214 -#define IDM_WINDOW_FONT_5 215 -#define IDM_WINDOW_FONT_6 216 -#define IDM_WINDOW_FONT_7 217 - -#define IDM_WINDOW_POS_0 220 -#define IDM_WINDOW_POS_1 221 -#define IDM_WINDOW_POS_2 222 -#define IDM_WINDOW_POS_3 223 -#define IDM_WINDOW_POS_4 224 -#define IDM_WINDOW_POS_5 225 -#define IDM_WINDOW_POS_6 226 -#define IDM_WINDOW_POS_7 227 - -#define IDM_WINDOW_BIZ_0 230 -#define IDM_WINDOW_BIZ_1 231 -#define IDM_WINDOW_BIZ_2 232 -#define IDM_WINDOW_BIZ_3 233 -#define IDM_WINDOW_BIZ_4 234 -#define IDM_WINDOW_BIZ_5 235 -#define IDM_WINDOW_BIZ_6 236 -#define IDM_WINDOW_BIZ_7 237 - -#define IDM_WINDOW_I_WID_0 240 -#define IDM_WINDOW_I_WID_1 241 -#define IDM_WINDOW_I_WID_2 242 -#define IDM_WINDOW_I_WID_3 243 -#define IDM_WINDOW_I_WID_4 244 -#define IDM_WINDOW_I_WID_5 245 -#define IDM_WINDOW_I_WID_6 246 -#define IDM_WINDOW_I_WID_7 247 - -#define IDM_WINDOW_D_WID_0 250 -#define IDM_WINDOW_D_WID_1 251 -#define IDM_WINDOW_D_WID_2 252 -#define IDM_WINDOW_D_WID_3 253 -#define IDM_WINDOW_D_WID_4 254 -#define IDM_WINDOW_D_WID_5 255 -#define IDM_WINDOW_D_WID_6 256 -#define IDM_WINDOW_D_WID_7 257 - -#define IDM_WINDOW_I_HGT_0 260 -#define IDM_WINDOW_I_HGT_1 261 -#define IDM_WINDOW_I_HGT_2 262 -#define IDM_WINDOW_I_HGT_3 263 -#define IDM_WINDOW_I_HGT_4 264 -#define IDM_WINDOW_I_HGT_5 265 -#define IDM_WINDOW_I_HGT_6 266 -#define IDM_WINDOW_I_HGT_7 267 - -#define IDM_WINDOW_D_HGT_0 270 -#define IDM_WINDOW_D_HGT_1 271 -#define IDM_WINDOW_D_HGT_2 272 -#define IDM_WINDOW_D_HGT_3 273 -#define IDM_WINDOW_D_HGT_4 274 -#define IDM_WINDOW_D_HGT_5 275 -#define IDM_WINDOW_D_HGT_6 276 -#define IDM_WINDOW_D_HGT_7 277 - -#define IDM_OPTIONS_NO_GRAPHICS 400 -#define IDM_OPTIONS_OLD_GRAPHICS 401 -#define IDM_OPTIONS_NEW_GRAPHICS 402 -#define IDM_OPTIONS_NEW2_GRAPHICS 403 -#define IDM_OPTIONS_BIGTILE 409 -#define IDM_OPTIONS_SOUND 410 -#define IDM_OPTIONS_MUSIC 411 -#define IDM_OPTIONS_SAVER 420 -#define IDM_OPTIONS_MAP 430 -#define IDM_OPTIONS_BG 440 -#define IDM_OPTIONS_OPEN_BG 441 - -#define IDM_DUMP_SCREEN_HTML 450 - -#define IDM_HELP_CONTENTS 901 - -/* - * Exclude parts of WINDOWS.H that are not needed - */ -#define NOCOMM /* Comm driver APIs and definitions */ -#define NOLOGERROR /* LogError() and related definitions */ -#define NOPROFILER /* Profiler APIs */ -#define NOLFILEIO /* _l* file I/O routines */ -#define NOOPENFILE /* OpenFile and related definitions */ -#define NORESOURCE /* Resource management */ -#define NOATOM /* Atom management */ -#define NOLANGUAGE /* Character test routines */ -#define NOLSTRING /* lstr* string management routines */ -#define NODBCS /* Double-byte character set routines */ -#define NOKEYBOARDINFO /* Keyboard driver routines */ -#define NOCOLOR /* COLOR_* color values */ -#define NODRAWTEXT /* DrawText() and related definitions */ -#define NOSCALABLEFONT /* Truetype scalable font support */ -#define NOMETAFILE /* Metafile support */ -#define NOSYSTEMPARAMSINFO /* SystemParametersInfo() and SPI_* definitions */ -#define NODEFERWINDOWPOS /* DeferWindowPos and related definitions */ -#define NOKEYSTATES /* MK_* message key state flags */ -#define NOWH /* SetWindowsHook and related WH_* definitions */ -#define NOCLIPBOARD /* Clipboard APIs and definitions */ -#define NOICONS /* IDI_* icon IDs */ -#define NOMDI /* MDI support */ -#define NOHELP /* Help support */ - -/* Not defined since it breaks Borland C++ 5.5 */ -/* #define NOCTLMGR */ /* Control management and controls */ - -/* - * Exclude parts of WINDOWS.H that are not needed (Win32) - */ -#define WIN32_LEAN_AND_MEAN -#define NONLS /* All NLS defines and routines */ -#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */ -#define NOKANJI /* Kanji support stuff. */ -#define NOMCX /* Modem Configuration Extensions */ - -/* - * Include the "windows" support file - */ -#include - -/* - * Exclude parts of MMSYSTEM.H that are not needed - */ -#define MMNODRV /* Installable driver support */ -#define MMNOWAVE /* Waveform support */ -#define MMNOMIDI /* MIDI support */ -#define MMNOAUX /* Auxiliary audio support */ -#define MMNOTIMER /* Timer support */ -#define MMNOJOY /* Joystick support */ -#define MMNOMCI /* MCI support */ -#define MMNOMMIO /* Multimedia file I/O support */ -#define MMNOMMSYSTEM /* General MMSYSTEM functions */ - -/* - * Include some more files. Note: the Cygnus Cygwin compiler - * doesn't use mmsystem.h instead it includes the winmm library - * which performs a similar function. - */ -#include -#include - -/* - * HTML-Help requires htmlhelp.h and htmlhelp.lib from Microsoft's - * HTML Workshop < http://msdn.microsoft.com/workshop/author/htmlhelp/ >. - */ -/* #define HTML_HELP */ - -#ifdef HTML_HELP -#include -#endif /* HTML_HELP */ - -/* - * Include the support for loading bitmaps - */ -#ifdef USE_GRAPHICS -# include "readdib.h" -#endif - -/* - * Hack -- Fake declarations from "dos.h" - */ -#ifdef WIN32 -#define INVALID_FILE_NAME (DWORD)0xFFFFFFFF -#else /* WIN32 */ -#define FA_LABEL 0x08 /* Volume label */ -#define FA_DIREC 0x10 /* Directory */ -unsigned _cdecl _dos_getfileattr(concptr , unsigned *); -#endif /* WIN32 */ - -/* - * Silliness in WIN32 drawing routine - */ -#ifdef WIN32 -# define MoveTo(H,X,Y) MoveToEx(H, X, Y, NULL) -#endif /* WIN32 */ - -/* - * Silliness for Windows 95 - */ -#ifndef WS_EX_TOOLWINDOW -# define WS_EX_TOOLWINDOW 0 -#endif - -/* - * Foreground color bits (hard-coded by DOS) - */ -#define VID_BLACK 0x00 -#define VID_BLUE 0x01 -#define VID_GREEN 0x02 -#define VID_CYAN 0x03 -#define VID_RED 0x04 -#define VID_MAGENTA 0x05 -#define VID_YELLOW 0x06 -#define VID_WHITE 0x07 - -/* - * Bright text (hard-coded by DOS) - */ -#define VID_BRIGHT 0x08 - -/* - * Background color bits (hard-coded by DOS) - */ -#define VUD_BLACK 0x00 -#define VUD_BLUE 0x10 -#define VUD_GREEN 0x20 -#define VUD_CYAN 0x30 -#define VUD_RED 0x40 -#define VUD_MAGENTA 0x50 -#define VUD_YELLOW 0x60 -#define VUD_WHITE 0x70 - -/* - * Blinking text (hard-coded by DOS) - */ -#define VUD_BRIGHT 0x80 - - -/* - * Forward declare - */ -typedef struct _term_data term_data; - -/*! - * @struct _term_data - * @brief ターム情報構造体 / Extra "term" data - * @details - *

- * pos_x / pos_y は各タームの左上点座標を指す。 - *

- *

- * tile_wid / tile_hgt は[ウィンドウ]メニューのタイルの幅/高さを~を - * 1ドットずつ調整するステータスを指す。 - * また、フォントを変更すると都度自動調整される。 - *

- *

- * Note the use of "font_want" for the names of the font file requested by - * the user, and the use of "font_file" for the currently active font file. - * - * The "font_file" is uppercased, and takes the form "8X13.FON", while - * "font_want" can be in almost any form as long as it could be construed - * as attempting to represent the name of a font. - *

- */ -struct _term_data -{ - term t; - concptr s; - HWND w; - DWORD dwStyle; - DWORD dwExStyle; - - uint keys; - TERM_LEN rows; /* int -> uint */ - TERM_LEN cols; - - uint pos_x; //!< タームの左上X座標 - uint pos_y; //!< タームの左上Y座標 - uint size_wid; - uint size_hgt; - uint size_ow1; - uint size_oh1; - uint size_ow2; - uint size_oh2; - - bool size_hack; - bool xtra_hack; - bool visible; - bool bizarre; - concptr font_want; - concptr font_file; - HFONT font_id; - int font_wid; //!< フォント横幅 - int font_hgt; //!< フォント縦幅 - int tile_wid; //!< タイル横幅 - int tile_hgt; //!< タイル縦幅 - - uint map_tile_wid; - uint map_tile_hgt; - - bool map_active; -#if 1 /* #ifdef JP */ - LOGFONT lf; -#endif - - bool posfix; - -}; - -#define MAX_TERM_DATA 8 //!< Maximum number of windows - -static term_data data[MAX_TERM_DATA]; //!< An array of term_data's -static term_data *my_td; //!< Hack -- global "window creation" pointer -POINT normsize; //!< Remember normal size of main window when maxmized - -/* - * was main window maximized on previous playing - */ -bool win_maximized = FALSE; - -/* - * game in progress - */ -bool game_in_progress = FALSE; - -/* - * note when "open"/"new" become valid - */ -bool initialized = FALSE; - -/* - * screen paletted, i.e. 256 colors - */ -bool paletted = FALSE; - -/* - * 16 colors screen, don't use RGB() - */ -bool colors16 = FALSE; - -/* - * Saved instance handle - */ -static HINSTANCE hInstance; - -/* - * Yellow brush for the cursor - */ -static HBRUSH hbrYellow; - -/* - * An icon - */ -static HICON hIcon; - -/* - * A palette - */ -static HPALETTE hPal; - -/* bg */ -static HBITMAP hBG = NULL; -static int use_bg = 0; //!< 背景使用フラグ、1なら私用。 -static char bg_bitmap_file[1024] = "bg.bmp"; //!< 現在の背景ビットマップファイル名。 - -#ifdef USE_SAVER - -/* - * The screen saver window - */ -static HWND hwndSaver; - -#endif /* USE_SAVER */ - - -#ifdef USE_GRAPHICS - -/*! - * 現在使用中のタイルID(0ならば未使用) - * Flag set once "graphics" has been initialized - */ -static byte_hack current_graphics_mode = 0; - -/* - * The global bitmap - */ -static DIBINIT infGraph; - -/* - * The global bitmap mask - */ -static DIBINIT infMask; - -#endif /* USE_GRAPHICS */ - - -#ifdef USE_SOUND - -/* - * Flag set once "sound" has been initialized - */ -static bool can_use_sound = FALSE; - -#define SAMPLE_MAX 8 -/* - * An array of sound file names - */ -static concptr sound_file[SOUND_MAX][SAMPLE_MAX]; - -#endif /* USE_SOUND */ - - - -#ifdef USE_MUSIC - -#define SAMPLE_MUSIC_MAX 16 -static concptr music_file[MUSIC_BASIC_MAX][SAMPLE_MUSIC_MAX]; -static concptr dungeon_music_file[1000][SAMPLE_MUSIC_MAX]; -static concptr town_music_file[1000][SAMPLE_MUSIC_MAX]; -static concptr quest_music_file[1000][SAMPLE_MUSIC_MAX]; -static bool can_use_music = FALSE; - -static MCI_OPEN_PARMS mop; -static char mci_device_type[256]; - -int current_music_type = 0; -int current_music_id = 0; - -#endif /* USE_MUSIC */ - - -/* - * Full path to ANGBAND.INI - */ -static concptr ini_file = NULL; - -/* - * Name of application - */ -static concptr AppName = "ANGBAND"; - -/* - * Name of sub-window type - */ -static concptr AngList = "AngList"; - -/* - * Directory names - */ -static concptr ANGBAND_DIR_XTRA_GRAF; -static concptr ANGBAND_DIR_XTRA_SOUND; -static concptr ANGBAND_DIR_XTRA_MUSIC; -static concptr ANGBAND_DIR_XTRA_HELP; -#if 0 /* #ifndef JP */ -static concptr ANGBAND_DIR_XTRA_FONT; -#endif -#ifdef USE_MUSIC -static concptr ANGBAND_DIR_XTRA_MUSIC; -#endif - - -/* - * The "complex" color values - */ -static COLORREF win_clr[256]; - - -/* - * Flag for macro trigger with dump ASCII - */ -static bool Term_no_press = FALSE; - -/* - * Copy and paste - */ -static bool mouse_down = FALSE; -static bool paint_rect = FALSE; -static TERM_LEN mousex = 0, mousey = 0; -static TERM_LEN oldx, oldy; - - -/*! - * @brief The "simple" color values - * @details - * See "main-ibm.c" for original table information - * The entries below are taken from the "color bits" defined above. - * Note that many of the choices below suck, but so do crappy monitors. - */ -static BYTE win_pal[256] = -{ - VID_BLACK, /* Dark */ - VID_WHITE, /* White */ - VID_CYAN, /* Slate XXX */ - VID_RED | VID_BRIGHT, /* Orange XXX */ - VID_RED, /* Red */ - VID_GREEN, /* Green */ - VID_BLUE, /* Blue */ - VID_YELLOW, /* Umber XXX */ - VID_BLACK | VID_BRIGHT, /* Light Dark */ - VID_CYAN | VID_BRIGHT, /* Light Slate XXX */ - VID_MAGENTA, /* Violet XXX */ - VID_YELLOW | VID_BRIGHT, /* Yellow */ - VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */ - VID_GREEN | VID_BRIGHT, /* Light Green */ - VID_BLUE | VID_BRIGHT, /* Light Blue */ - VID_YELLOW /* Light Umber XXX */ -}; - - -/* - * Hack -- define which keys are "special" - */ -static bool special_key[256]; -static bool ignore_key[256]; - -#if 1 -/* - * Hack -- initialization list for "special_key" - */ -static byte special_key_list[] = { - VK_CLEAR, VK_PAUSE, VK_CAPITAL, - VK_KANA, VK_JUNJA, VK_FINAL, VK_KANJI, - VK_CONVERT, VK_NONCONVERT, VK_ACCEPT, VK_MODECHANGE, - VK_PRIOR, VK_NEXT, VK_END, VK_HOME, - VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, - VK_SELECT, VK_PRINT, VK_EXECUTE, VK_SNAPSHOT, - VK_INSERT, VK_DELETE, VK_HELP, VK_APPS, - VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, - VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, - VK_NUMPAD8, VK_NUMPAD9, VK_MULTIPLY, VK_ADD, - VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE, - VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, - VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, - VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, - VK_F19,VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, - VK_NUMLOCK, VK_SCROLL, VK_ATTN, VK_CRSEL, - VK_EXSEL, VK_EREOF, VK_PLAY, VK_ZOOM, - VK_NONAME, VK_PA1, - 0 /* End of List */ -}; - -static byte ignore_key_list[] = { - VK_ESCAPE, VK_TAB, VK_SPACE, - 'F', 'W', 'O', /*'H',*/ /* these are menu characters.*/ - VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN, - VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, - VK_LMENU, VK_RMENU, - 0 /* End of List */ -}; -#else -/* - * Hack -- initialization list for "special_key" - * - * We ignore the modifier keys (shift, control, alt, num lock, scroll lock), - * and the normal keys (escape, tab, return, letters, numbers, etc), but we - * catch the keypad keys (with and without numlock set, including keypad 5), - * the function keys (including the "menu" key which maps to F10), and the - * "pause" key (between scroll lock and numlock). We also catch a few odd - * keys which I do not recognize, but which are listed among keys which we - * do catch, so they should be harmless to catch. - */ -static byte special_key_list[] = -{ - VK_CLEAR, /* 0x0C (KP<5>) */ - - VK_PAUSE, /* 0x13 (pause) */ - - VK_PRIOR, /* 0x21 (KP<9>) */ - VK_NEXT, /* 0x22 (KP<3>) */ - VK_END, /* 0x23 (KP<1>) */ - VK_HOME, /* 0x24 (KP<7>) */ - VK_LEFT, /* 0x25 (KP<4>) */ - VK_UP, /* 0x26 (KP<8>) */ - VK_RIGHT, /* 0x27 (KP<6>) */ - VK_DOWN, /* 0x28 (KP<2>) */ - VK_SELECT, /* 0x29 (?????) */ - VK_PRINT, /* 0x2A (?????) */ - VK_EXECUTE, /* 0x2B (?????) */ - VK_SNAPSHOT, /* 0x2C (?????) */ - VK_INSERT, /* 0x2D (KP<0>) */ - VK_DELETE, /* 0x2E (KP<.>) */ - VK_HELP, /* 0x2F (?????) */ -#if 0 - VK_NUMPAD0, /* 0x60 (KP<0>) */ - VK_NUMPAD1, /* 0x61 (KP<1>) */ - VK_NUMPAD2, /* 0x62 (KP<2>) */ - VK_NUMPAD3, /* 0x63 (KP<3>) */ - VK_NUMPAD4, /* 0x64 (KP<4>) */ - VK_NUMPAD5, /* 0x65 (KP<5>) */ - VK_NUMPAD6, /* 0x66 (KP<6>) */ - VK_NUMPAD7, /* 0x67 (KP<7>) */ - VK_NUMPAD8, /* 0x68 (KP<8>) */ - VK_NUMPAD9, /* 0x69 (KP<9>) */ - VK_MULTIPLY, /* 0x6A (KP<*>) */ - VK_ADD, /* 0x6B (KP<+>) */ - VK_SEPARATOR, /* 0x6C (?????) */ - VK_SUBTRACT, /* 0x6D (KP<->) */ - VK_DECIMAL, /* 0x6E (KP<.>) */ - VK_DIVIDE, /* 0x6F (KP) */ -#endif - VK_F1, /* 0x70 */ - VK_F2, /* 0x71 */ - VK_F3, /* 0x72 */ - VK_F4, /* 0x73 */ - VK_F5, /* 0x74 */ - VK_F6, /* 0x75 */ - VK_F7, /* 0x76 */ - VK_F8, /* 0x77 */ - VK_F9, /* 0x78 */ - VK_F10, /* 0x79 */ - VK_F11, /* 0x7A */ - VK_F12, /* 0x7B */ - VK_F13, /* 0x7C */ - VK_F14, /* 0x7D */ - VK_F15, /* 0x7E */ - VK_F16, /* 0x7F */ - VK_F17, /* 0x80 */ - VK_F18, /* 0x81 */ - VK_F19, /* 0x82 */ - VK_F20, /* 0x83 */ - VK_F21, /* 0x84 */ - VK_F22, /* 0x85 */ - VK_F23, /* 0x86 */ - VK_F24, /* 0x87 */ - 0 -}; -#endif - - -/* Function prototype */ - -static bool is_already_running(void); - - -/* bg */ -static void delete_bg(void) -{ - if (hBG != NULL) - { - DeleteObject(hBG); - hBG = NULL; - } -} - -static int init_bg(void) -{ - char * bmfile = bg_bitmap_file; - - delete_bg(); - if (use_bg == 0) return 0; - - hBG = LoadImage(NULL, bmfile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); - if (!hBG) { - plog_fmt(_("壁紙用ビットマップ '%s' を読み込めません。", "Can't load the bitmap file '%s'."), bmfile); - use_bg = 0; - return 0; - } - use_bg = 1; - return 1; -} - -static void DrawBG(HDC hdc, RECT *r) -{ - HDC hdcSrc; - HBITMAP hOld; - BITMAP bm; - int x = r->left, y = r->top; - int nx, ny, sx, sy, swid, shgt, cwid, chgt; - - if (!use_bg || !hBG) - return; - - nx = x; ny = y; - GetObject(hBG, sizeof(bm), &bm); - swid = bm.bmWidth; shgt = bm.bmHeight; - - hdcSrc = CreateCompatibleDC(hdc); - hOld = SelectObject(hdcSrc, hBG); - - do { - sx = nx % swid; - cwid = MIN(swid - sx, r->right - nx); - do { - sy = ny % shgt; - chgt = MIN(shgt - sy, r->bottom - ny); - BitBlt(hdc, nx, ny, cwid, chgt, hdcSrc, sx, sy, SRCCOPY); - ny += chgt; - } while (ny < r->bottom); - ny = y; - nx += cwid; - } while (nx < r->right); - - SelectObject(hdcSrc, hOld); - DeleteDC(hdcSrc); -} - -#if 0 -/* - * Hack -- given a pathname, point at the filename - */ -static concptr extract_file_name(concptr s) -{ - concptr p; - - /* Start at the end */ - p = s + strlen(s) - 1; - - /* Back up to divider */ - while ((p >= s) && (*p != ':') && (*p != '\\')) p--; - - /* Return file name */ - return (p+1); -} -#endif - - -/* - * Hack -- given a simple filename, extract the "font size" info - * - * Return a pointer to a static buffer holding the capitalized base name. - */ -#if 0 /* #ifndef JP */ -static char *analyze_font(char *path, int *wp, int *hp) -{ - int wid, hgt; - - char *s, *p; - - /* Start at the end */ - p = path + strlen(path) - 1; - - /* Back up to divider */ - while ((p >= path) && (*p != ':') && (*p != '\\')) --p; - - /* Advance to file name */ - ++p; - - /* Capitalize */ - for (s = p; *s; ++s) - { - /* Capitalize (be paranoid) */ - if (islower(*s)) *s = toupper(*s); - } - - /* Find first 'X' */ - s = my_strchr(p, 'X'); - - /* Extract font width */ - wid = atoi(p); - - /* Extract height */ - hgt = s ? atoi(s+1) : 0; - - /* Save results */ - (*wp) = wid; - (*hp) = hgt; - return (p); -} -#endif - - -/* - * Check for existance of a file - */ -static bool check_file(concptr s) -{ - char path[1024]; - -#ifdef WIN32 - - DWORD attrib; - -#else /* WIN32 */ - - unsigned int attrib; - -#endif /* WIN32 */ - - /* Copy it */ - strcpy(path, s); - -#ifdef WIN32 - - /* Examine */ - attrib = GetFileAttributes(path); - - /* Require valid filename */ - if (attrib == INVALID_FILE_NAME) return (FALSE); - - /* Prohibit directory */ - if (attrib & FILE_ATTRIBUTE_DIRECTORY) return (FALSE); - -#else /* WIN32 */ - - /* Examine and verify */ - if (_dos_getfileattr(path, &attrib)) return (FALSE); - - /* Prohibit something */ - if (attrib & FA_LABEL) return (FALSE); - - /* Prohibit directory */ - if (attrib & FA_DIREC) return (FALSE); - -#endif /* WIN32 */ - - /* Success */ - return (TRUE); -} - - -/* - * Check for existance of a directory - */ -static bool check_dir(concptr s) -{ - int i; - - char path[1024]; - -#ifdef WIN32 - - DWORD attrib; - -#else /* WIN32 */ - - unsigned int attrib; - -#endif /* WIN32 */ - - /* Copy it */ - strcpy(path, s); - - /* Check length */ - i = strlen(path); - - /* Remove trailing backslash */ - if (i && (path[i-1] == '\\')) path[--i] = '\0'; - -#ifdef WIN32 - - /* Examine */ - attrib = GetFileAttributes(path); - - /* Require valid filename */ - if (attrib == INVALID_FILE_NAME) return (FALSE); - - /* Require directory */ - if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) return (FALSE); - -#else /* WIN32 */ - - /* Examine and verify */ - if (_dos_getfileattr(path, &attrib)) return (FALSE); - - /* Prohibit something */ - if (attrib & FA_LABEL) return (FALSE); - - /* Require directory */ - if (!(attrib & FA_DIREC)) return (FALSE); - -#endif /* WIN32 */ - - /* Success */ - return (TRUE); -} - - -/* - * Validate a file - */ -static void validate_file(concptr s) -{ - /* Verify or fail */ - if (!check_file(s)) - { - quit_fmt(_("必要なファイル[%s]が見あたりません。", "Cannot find required file:\n%s"), s); - } -} - - -/* - * Validate a directory - */ -static void validate_dir(concptr s, bool vital) -{ - /* Verify or fail */ - if (!check_dir(s)) - { - /* This directory contains needed data */ - if (vital) - { - quit_fmt(_("必要なディレクトリ[%s]が見あたりません。", "Cannot find required directory:\n%s"), s); - } - /* Attempt to create this directory */ - else if (mkdir(s)) - { - quit_fmt("Unable to create directory:\n%s", s); - } - } -} - - -/*! - * @brief (Windows版固有実装)Get the "size" for a window - */ -static void term_getsize(term_data *td) -{ - RECT rc; - TERM_LEN wid, hgt; - - /* Paranoia */ - if (td->cols < 1) td->cols = 1; - if (td->rows < 1) td->rows = 1; - - /* Window sizes */ - wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2; - hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2; - - /* Fake window size */ - rc.left = 0; - rc.right = rc.left + wid; - rc.top = 0; - rc.bottom = rc.top + hgt; - - /* rc.right += 1; */ - /* rc.bottom += 1; */ - - /* Adjust */ - AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); - - /* Total size */ - td->size_wid = rc.right - rc.left; - td->size_hgt = rc.bottom - rc.top; - - /* See CreateWindowEx */ - if (!td->w) return; - - /* Extract actual location */ - GetWindowRect(td->w, &rc); - - /* Save the location */ - td->pos_x = rc.left; - td->pos_y = rc.top; -} - - -/* - * Write the "prefs" for a single term - */ -static void save_prefs_aux(int i) -{ - term_data *td = &data[i]; - GAME_TEXT sec_name[128]; - char buf[1024]; - - RECT rc; - WINDOWPLACEMENT lpwndpl; - - /* Paranoia */ - if (!td->w) return; - - /* Make section name */ - sprintf(sec_name, "Term-%d", i); - - /* Visible */ - if (i > 0) - { - strcpy(buf, td->visible ? "1" : "0"); - WritePrivateProfileString(sec_name, "Visible", buf, ini_file); - } - - /* Font */ -#ifdef JP - strcpy(buf, td->lf.lfFaceName[0]!='\0' ? td->lf.lfFaceName : "MS ゴシック"); -#else -#if 0 - strcpy(buf, td->font_file ? td->font_file : "8X13.FON"); -#else - strcpy(buf, td->lf.lfFaceName[0]!='\0' ? td->lf.lfFaceName : "Courier"); -#endif -#endif - - WritePrivateProfileString(sec_name, "Font", buf, ini_file); - -#if 1 /* #ifdef JP */ - wsprintf(buf, "%d", td->lf.lfWidth); - WritePrivateProfileString(sec_name, "FontWid", buf, ini_file); - wsprintf(buf, "%d", td->lf.lfHeight); - WritePrivateProfileString(sec_name, "FontHgt", buf, ini_file); - wsprintf(buf, "%d", td->lf.lfWeight); - WritePrivateProfileString(sec_name, "FontWgt", buf, ini_file); -#endif - /* Bizarre */ - strcpy(buf, td->bizarre ? "1" : "0"); - WritePrivateProfileString(sec_name, "Bizarre", buf, ini_file); - - /* Tile size (x) */ - wsprintf(buf, "%d", td->tile_wid); - WritePrivateProfileString(sec_name, "TileWid", buf, ini_file); - - /* Tile size (y) */ - wsprintf(buf, "%d", td->tile_hgt); - WritePrivateProfileString(sec_name, "TileHgt", buf, ini_file); - - /* Get window placement and dimensions */ - lpwndpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(td->w, &lpwndpl); - - /* Acquire position in *normal* mode (not minimized) */ - rc = lpwndpl.rcNormalPosition; - - /* Window size (x) */ - if (i == 0) wsprintf(buf, "%d", normsize.x); - else wsprintf(buf, "%d", td->cols); - WritePrivateProfileString(sec_name, "NumCols", buf, ini_file); - - /* Window size (y) */ - if (i == 0) wsprintf(buf, "%d", normsize.y); - else wsprintf(buf, "%d", td->rows); - WritePrivateProfileString(sec_name, "NumRows", buf, ini_file); - - /* Maxmized (only main window) */ - if (i == 0) - { - strcpy(buf, IsZoomed(td->w) ? "1" : "0"); - WritePrivateProfileString(sec_name, "Maximized", buf, ini_file); - } - - /* Acquire position */ - GetWindowRect(td->w, &rc); - - /* Window position (x) */ - wsprintf(buf, "%d", rc.left); - WritePrivateProfileString(sec_name, "PositionX", buf, ini_file); - - /* Window position (y) */ - wsprintf(buf, "%d", rc.top); - WritePrivateProfileString(sec_name, "PositionY", buf, ini_file); - - /* Window Z position */ - if (i > 0) - { - strcpy(buf, td->posfix ? "1" : "0"); - WritePrivateProfileString(sec_name, "PositionFix", buf, ini_file); - } -} - - -/* - * Write the "prefs" - * We assume that the windows have all been initialized - */ -static void save_prefs(void) -{ - int i; - - char buf[128]; - - /* Save the "arg_graphics" flag */ - sprintf(buf, "%d", arg_graphics); - WritePrivateProfileString("Angband", "Graphics", buf, ini_file); - - /* Save the "arg_bigtile" flag */ - strcpy(buf, arg_bigtile ? "1" : "0"); - WritePrivateProfileString("Angband", "Bigtile", buf, ini_file); - - /* Save the "arg_sound" flag */ - strcpy(buf, arg_sound ? "1" : "0"); - WritePrivateProfileString("Angband", "Sound", buf, ini_file); - - /* Save the "arg_sound" flag */ - strcpy(buf, arg_music ? "1" : "0"); - WritePrivateProfileString("Angband", "Music", buf, ini_file); - - /* bg */ - strcpy(buf, use_bg ? "1" : "0"); - WritePrivateProfileString("Angband", "BackGround", buf, ini_file); - WritePrivateProfileString("Angband", "BackGroundBitmap", - bg_bitmap_file[0] != '\0' ? bg_bitmap_file : "bg.bmp", ini_file); - - /* Save window prefs */ - for (i = 0; i < MAX_TERM_DATA; ++i) - { - save_prefs_aux(i); - } -} - - -/* - * Load the "prefs" for a single term - */ -static void load_prefs_aux(int i) -{ - term_data *td = &data[i]; - GAME_TEXT sec_name[128]; - char tmp[1024]; - - int wid, hgt, posx, posy; - int dispx = GetSystemMetrics( SM_CXVIRTUALSCREEN); - int dispy = GetSystemMetrics( SM_CYVIRTUALSCREEN); - posx=0; - posy=0; - - /* Make section name */ - sprintf(sec_name, "Term-%d", i); - - /* Make section name */ - sprintf(sec_name, "Term-%d", i); - - /* Visible */ - if (i > 0) - { - td->visible = (GetPrivateProfileInt(sec_name, "Visible", td->visible, ini_file) != 0); - } - - /* Desired font, with default */ -#ifdef JP - GetPrivateProfileString(sec_name, "Font", "MS ゴシック", tmp, 127, ini_file); -#else -#if 0 - GetPrivateProfileString(sec_name, "Font", "8X13.FON", tmp, 127, ini_file); -#else - GetPrivateProfileString(sec_name, "Font", "Courier", tmp, 127, ini_file); -#endif -#endif - - - /* Bizarre */ - td->bizarre = (GetPrivateProfileInt(sec_name, "Bizarre", td->bizarre, ini_file) != 0); - - /* Analyze font, save desired font name */ -#if 1 /* #ifdef JP */ - td->font_want = string_make(tmp); - hgt = 15; wid = 0; - td->lf.lfWidth = GetPrivateProfileInt(sec_name, "FontWid", wid, ini_file); - td->lf.lfHeight = GetPrivateProfileInt(sec_name, "FontHgt", hgt, ini_file); - td->lf.lfWeight = GetPrivateProfileInt(sec_name, "FontWgt", 0, ini_file); -#else - td->font_want = string_make(analyze_font(tmp, &wid, &hgt)); -#endif - - - /* Tile size */ -#if 1 /* #ifdef JP */ - td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", td->lf.lfWidth, ini_file); - td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", td->lf.lfHeight, ini_file); -#else - td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", wid, ini_file); - td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", hgt, ini_file); -#endif - - - /* Window size */ - td->cols = GetPrivateProfileInt(sec_name, "NumCols", td->cols, ini_file); - td->rows = GetPrivateProfileInt(sec_name, "NumRows", td->rows, ini_file); - normsize.x = td->cols; normsize.y = td->rows; - - /* Window size */ - if (i == 0) - { - win_maximized = (GetPrivateProfileInt(sec_name, "Maximized", win_maximized, ini_file) != 0); - } - - /* Window position */ - posx = GetPrivateProfileInt(sec_name, "PositionX", posx, ini_file); - posy = GetPrivateProfileInt(sec_name, "PositionY", posy, ini_file); - td->pos_x = MIN(MAX(0, posx), dispx-128); - td->pos_y = MIN(MAX(0, posy), dispy-128); - - /* Window Z position */ - if (i > 0) - { - td->posfix = (GetPrivateProfileInt(sec_name, "PositionFix", td->posfix, ini_file) != 0); - } -} - - -/* - * Load the "prefs" - */ -static void load_prefs(void) -{ - int i; - - /* Extract the "arg_graphics" flag */ - arg_graphics = (byte_hack)GetPrivateProfileInt("Angband", "Graphics", GRAPHICS_NONE, ini_file); - - /* Extract the "arg_bigtile" flag */ - arg_bigtile = (GetPrivateProfileInt("Angband", "Bigtile", FALSE, ini_file) != 0); - use_bigtile = arg_bigtile; - - /* Extract the "arg_sound" flag */ - arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0); - - /* Extract the "arg_sound" flag */ - arg_music = (GetPrivateProfileInt("Angband", "Music", 0, ini_file) != 0); - - /* bg */ - use_bg = GetPrivateProfileInt("Angband", "BackGround", 0, ini_file); - GetPrivateProfileString("Angband", "BackGroundBitmap", "bg.bmp", bg_bitmap_file, 1023, ini_file); - - /* Load window prefs */ - for (i = 0; i < MAX_TERM_DATA; ++i) - { - load_prefs_aux(i); - } -} - -#if defined(USE_SOUND) || defined(USE_MUSIC) - -/* - * - Taken from files.c. - * - * Extract "tokens" from a buffer - * - * This function uses "whitespace" as delimiters, and treats any amount of - * whitespace as a single delimiter. We will never return any empty tokens. - * When given an empty buffer, or a buffer containing only "whitespace", we - * will return no tokens. We will never extract more than "num" tokens. - * - * By running a token through the "text_to_ascii()" function, you can allow - * that token to include (encoded) whitespace, using "\s" to encode spaces. - * - * We save pointers to the tokens in "tokens", and return the number found. - */ -static s16b tokenize_whitespace(char *buf, s16b num, char **tokens) -{ - s16b k = 0; - char *s = buf; - - /* Process */ - while (k < num) - { - char *t; - - /* Skip leading whitespace */ - for ( ; *s && iswspace(*s); ++s) /* loop */; - - /* All done */ - if (!*s) break; - - /* Find next whitespace, if any */ - for (t = s; *t && !iswspace(*t); ++t) /* loop */; - - /* Nuke and advance (if necessary) */ - if (*t) *t++ = '\0'; - - /* Save the token */ - tokens[k++] = s; - - /* Advance */ - s = t; - } - - /* Count */ - return (k); -} - -#endif /* USE_SOUND || USE_MUSIC */ - -#ifdef USE_SOUND - -static void load_sound_prefs(void) -{ - int i, j, num; - char tmp[1024]; - char ini_path[1024]; - char wav_path[1024]; - char *zz[SAMPLE_MAX]; - - /* Access the sound.cfg */ - - path_build(ini_path, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.cfg"); - - for (i = 0; i < SOUND_MAX; i++) - { - GetPrivateProfileString("Sound", angband_sound_name[i], "", tmp, 1024, ini_path); - - num = tokenize_whitespace(tmp, SAMPLE_MAX, zz); - - for (j = 0; j < num; j++) - { - /* Access the sound */ - path_build(wav_path, 1024, ANGBAND_DIR_XTRA_SOUND, zz[j]); - - /* Save the sound filename, if it exists */ - if (check_file(wav_path)) - sound_file[i][j] = string_make(zz[j]); - } - } -} - -#endif /* USE_SOUND */ - -#ifdef USE_MUSIC - -static void load_music_prefs(void) -{ - int i, j, num; - char tmp[1024]; - char ini_path[1024]; - char wav_path[1024]; - char *zz[SAMPLE_MAX]; - char key[80]; - - /* Access the music.cfg */ - - path_build(ini_path, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.cfg"); - - GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path); - - for (i = 0; i < MUSIC_BASIC_MAX; i++) - { - GetPrivateProfileString("Basic", angband_music_basic_name[i], "", tmp, 1024, ini_path); - - num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); - - for (j = 0; j < num; j++) - { - /* Access the sound */ - path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); - - /* Save the sound filename, if it exists */ - if (check_file(wav_path)) - music_file[i][j] = string_make(zz[j]); - } - } - - for (i = 0; i < max_d_idx; i++) - { - sprintf(key, "dungeon%03d", i); - GetPrivateProfileString("Dungeon", key, "", tmp, 1024, ini_path); - - num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); - - for (j = 0; j < num; j++) - { - /* Access the sound */ - path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); - - /* Save the sound filename, if it exists */ - if (check_file(wav_path)) - dungeon_music_file[i][j] = string_make(zz[j]); - } - } - - for (i = 0; i < max_q_idx; i++) - { - sprintf(key, "quest%03d", i); - GetPrivateProfileString("Quest", key, "", tmp, 1024, ini_path); - - num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); - - for (j = 0; j < num; j++) - { - /* Access the sound */ - path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); - - /* Save the sound filename, if it exists */ - if (check_file(wav_path)) - quest_music_file[i][j] = string_make(zz[j]); - } - } - - for (i = 0; i < 1000; i++) /*!< @todo 町最大数指定 */ - { - sprintf(key, "town%03d", i); - GetPrivateProfileString("Town", key, "", tmp, 1024, ini_path); - - num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); - - for (j = 0; j < num; j++) - { - /* Access the sound */ - path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); - - /* Save the sound filename, if it exists */ - if (check_file(wav_path)) - town_music_file[i][j] = string_make(zz[j]); - } - } - - -} - -#endif /* USE_MUSIC */ - -/* - * Create the new global palette based on the bitmap palette - * (if any), and the standard 16 entry palette derived from - * "win_clr[]" which is used for the basic 16 Angband colors. - * - * This function is never called before all windows are ready. - * - * This function returns FALSE if the new palette could not be - * prepared, which should normally be a fatal error. XXX XXX - * - * Note that only some machines actually use a "palette". - */ -static int new_palette(void) -{ - HPALETTE hBmPal; - HPALETTE hNewPal; - HDC hdc; - int i, nEntries; - int pLogPalSize; - int lppeSize; - LPLOGPALETTE pLogPal; - LPPALETTEENTRY lppe; - - term_data *td; - - - /* This makes no sense */ - if (!paletted) return (TRUE); - - - /* No bitmap */ - lppeSize = 0; - lppe = NULL; - nEntries = 0; - -#ifdef USE_GRAPHICS - - /* Check the bitmap palette */ - hBmPal = infGraph.hPalette; - - /* Use the bitmap */ - if (hBmPal) - { - lppeSize = 256 * sizeof(PALETTEENTRY); - lppe = (LPPALETTEENTRY)ralloc(lppeSize); - nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe); - if ((nEntries == 0) || (nEntries > 220)) - { - /* Warn the user */ - plog(_("画面を16ビットか24ビットカラーモードにして下さい。", "Please switch to high- or true-color mode.")); - - /* Cleanup */ - rnfree(lppe, lppeSize); - - /* Fail */ - return (FALSE); - } - } - -#endif /* USE_GRAPHICS */ - - /* Size of palette */ - pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY); - - /* Allocate palette */ - pLogPal = (LPLOGPALETTE)ralloc(pLogPalSize); - - /* Version */ - pLogPal->palVersion = 0x300; - - /* Make room for bitmap and normal data */ - pLogPal->palNumEntries = nEntries + 16; - - /* Save the bitmap data */ - for (i = 0; i < nEntries; i++) - { - pLogPal->palPalEntry[i] = lppe[i]; - } - - /* Save the normal data */ - for (i = 0; i < 16; i++) - { - LPPALETTEENTRY p; - - /* Access the entry */ - p = &(pLogPal->palPalEntry[i+nEntries]); - - /* Save the colors */ - p->peRed = GetRValue(win_clr[i]); - p->peGreen = GetGValue(win_clr[i]); - p->peBlue = GetBValue(win_clr[i]); - - /* Save the flags */ - p->peFlags = PC_NOCOLLAPSE; - } - - /* Free something */ - if (lppe) rnfree(lppe, lppeSize); - - /* Create a new palette, or fail */ - hNewPal = CreatePalette(pLogPal); - if (!hNewPal) quit(_("パレットを作成できません!", "Cannot create palette!")); - - /* Free the palette */ - rnfree(pLogPal, pLogPalSize); - - /* Main window */ - td = &data[0]; - - /* Realize the palette */ - hdc = GetDC(td->w); - SelectPalette(hdc, hNewPal, 0); - i = RealizePalette(hdc); - ReleaseDC(td->w, hdc); - if (i == 0) quit(_("パレットをシステムエントリにマップできません!", "Cannot realize palette!")); - - - /* Sub-windows */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - td = &data[i]; - - hdc = GetDC(td->w); - SelectPalette(hdc, hNewPal, 0); - ReleaseDC(td->w, hdc); - } - - /* Delete old palette */ - if (hPal) DeleteObject(hPal); - - /* Save new palette */ - hPal = hNewPal; - - /* Success */ - return (TRUE); -} - - -#ifdef USE_GRAPHICS -/*! - * @brief グラフィクスを初期化する / Initialize graphics - * @details - *
    - *
  • メニュー[オプション]>[グラフィクス]が「なし」以外の時に描画処理を初期化する。
  • - *
  • 呼び出されるタイミングはロード時、及び同メニューで「なし」以外に変更される毎になる。
  • - *
- */ -static bool init_graphics(void) -{ - /* Initialize once */ - char buf[1024]; - BYTE wid, hgt, twid, thgt, ox, oy; - concptr name; - - if (arg_graphics == GRAPHICS_ADAM_BOLT) - { - wid = 16; - hgt = 16; - twid = 16; - thgt = 16; - ox = 0; - oy = 0; - name = "16X16.BMP"; - - ANGBAND_GRAF = "new"; - } - else if (arg_graphics == GRAPHICS_HENGBAND) - { - /*! @todo redraw - wid = 64; - hgt = 64; - twid = 32; - thgt = 32; - ox = -16; - oy = -24; - name = "64X64.BMP"; - */ - - wid = 32; - hgt = 32; - twid = 32; - thgt = 32; - ox = 0; - oy = 0; - name = "32X32.BMP"; - - ANGBAND_GRAF = "ne2"; - } - else - { - wid = 8; - hgt = 8; - twid = 8; - thgt = 8; - ox = 0; - oy = 0; - name = "8X8.BMP"; - ANGBAND_GRAF = "old"; - } - - /* Access the bitmap file */ - path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name); - - /* Load the bitmap or quit */ - if (!ReadDIB(data[0].w, buf, &infGraph)) - { - plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name); - return (FALSE); - } - - /* Save the new sizes */ - infGraph.CellWidth = wid; - infGraph.CellHeight = hgt; - infGraph.TileWidth = twid; - infGraph.TileHeight = thgt; - infGraph.OffsetX = ox; - infGraph.OffsetY = oy; - - if (arg_graphics == GRAPHICS_ADAM_BOLT) - { - /* Access the mask file */ - path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask.bmp"); - - /* Load the bitmap or quit */ - if (!ReadDIB(data[0].w, buf, &infMask)) - { - plog_fmt("Cannot read bitmap file '%s'", buf); - return (FALSE); - } - } - if (arg_graphics == GRAPHICS_HENGBAND) - { - /* Access the mask file */ - path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask32.bmp"); - - /* Load the bitmap or quit */ - if (!ReadDIB(data[0].w, buf, &infMask)) - { - plog_fmt("Cannot read bitmap file '%s'", buf); - return (FALSE); - } - } - - /* Activate a palette */ - if (!new_palette()) - { - /* Free bitmap */ - - plog(_("パレットを実現できません!", "Cannot activate palette!")); - return (FALSE); - } - - /* Graphics available */ - current_graphics_mode = arg_graphics; - return (current_graphics_mode); -} -#endif /* USE_GRAPHICS */ - - -#ifdef USE_MUSIC -/* - * Initialize music - */ -static bool init_music(void) -{ - /* Initialize once */ - if (!can_use_music) - { - /* Load the prefs */ - load_music_prefs(); - - /* Sound available */ - can_use_music = TRUE; - } - return (can_use_music); -} - -/* - * Hack -- Stop a music - */ -static void stop_music(void) -{ - mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); - mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); -} - -#endif /* USE_MUSIC */ - -#ifdef USE_SOUND -/* - * Initialize sound - */ -static bool init_sound(void) -{ - /* Initialize once */ - if (!can_use_sound) - { - /* Load the prefs */ - load_sound_prefs(); - - /* Sound available */ - can_use_sound = TRUE; - } - return (can_use_sound); -} -#endif /* USE_SOUND */ - - -/* - * Resize a window - */ -static void term_window_resize(term_data *td) -{ - /* Require window */ - if (!td->w) return; - - /* Resize the window */ - SetWindowPos(td->w, 0, 0, 0, - td->size_wid, td->size_hgt, - SWP_NOMOVE | SWP_NOZORDER); - - /* Redraw later */ - InvalidateRect(td->w, NULL, TRUE); -} - - -/* - * Force the use of a new "font file" for a term_data - * - * This function may be called before the "window" is ready - * - * This function returns zero only if everything succeeds. - * - * Note that the "font name" must be capitalized!!! - */ -static errr term_force_font(term_data *td, concptr path) -{ - int wid, hgt; - -#if 0 /* #ifndef JP */ - int i; - char *base; - char buf[1024]; -#endif - - /* Forget the old font (if needed) */ - if (td->font_id) DeleteObject(td->font_id); - -#if 1 /* #ifdef JP */ - /* Unused */ - (void)path; - - /* Create the font (using the 'base' of the font file name!) */ - td->font_id = CreateFontIndirect(&(td->lf)); - wid = td->lf.lfWidth; - hgt = td->lf.lfHeight; - if (!td->font_id) return (1); -#else - /* Forget old font */ - if (td->font_file) - { - bool used = FALSE; - - /* Scan windows */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - /* Don't check when closing the application */ - if (!path) break; - - /* Check "screen" */ - if ((td != &data[i]) && - (data[i].font_file) && - (streq(data[i].font_file, td->font_file))) - { - used = TRUE; - } - } - - /* Remove unused font resources */ - if (!used) RemoveFontResource(td->font_file); - - /* Free the old name */ - string_free(td->font_file); - - /* Forget it */ - td->font_file = NULL; - } - - /* No path given */ - if (!path) return (1); - - /* Local copy */ - strcpy(buf, path); - - /* Analyze font path */ - base = analyze_font(buf, &wid, &hgt); - - /* Verify suffix */ - if (!suffix(base, ".FON")) return (1); - - /* Verify file */ - if (!check_file(buf)) return (1); - - /* Load the new font */ - if (!AddFontResource(buf)) return (1); - - /* Save new font name */ - td->font_file = string_make(base); - - /* Remove the "suffix" */ - base[strlen(base)-4] = '\0'; - - /* Create the font (using the 'base' of the font file name!) */ - td->font_id = CreateFont(hgt, wid, 0, 0, FW_DONTCARE, 0, 0, 0, - ANSI_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, - FIXED_PITCH | FF_DONTCARE, base); -#endif - - /* Hack -- Unknown size */ - if (!wid || !hgt) - { - HDC hdcDesktop; - HFONT hfOld; - TEXTMETRIC tm; - - /* all this trouble to get the cell size */ - hdcDesktop = GetDC(HWND_DESKTOP); - hfOld = SelectObject(hdcDesktop, td->font_id); - GetTextMetrics(hdcDesktop, &tm); - SelectObject(hdcDesktop, hfOld); - ReleaseDC(HWND_DESKTOP, hdcDesktop); - - /* Font size info */ - wid = tm.tmAveCharWidth; - hgt = tm.tmHeight; - } - - /* Save the size info */ - td->font_wid = wid; - td->font_hgt = hgt; - - /* Success */ - return (0); -} - - - -/* - * Allow the user to change the font for this window. - */ -static void term_change_font(term_data *td) -{ -#if 1 /* #ifdef JP */ - CHOOSEFONT cf; - - memset(&cf, 0, sizeof(cf)); - cf.lStructSize = sizeof(cf); - cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_NOVERTFONTS | CF_INITTOLOGFONTSTRUCT; - cf.lpLogFont = &(td->lf); - - if (ChooseFont(&cf)) - { - /* Force the font */ - term_force_font(td, NULL); - - /* Assume not bizarre */ - td->bizarre = TRUE; - - /* Reset the tile info */ - td->tile_wid = td->font_wid; - td->tile_hgt = td->font_hgt; - - /* Analyze the font */ - term_getsize(td); - - /* Resize the window */ - term_window_resize(td); - } - -#else - OPENFILENAME ofn; - - char tmp[1024] = ""; - - /* Extract a default if possible */ - if (td->font_file) strcpy(tmp, td->font_file); - - /* Ask for a choice */ - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = data[0].w; - ofn.lpstrFilter = "Angband Font Files (*.fon)\0*.fon\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = tmp; - ofn.nMaxFile = 128; - ofn.lpstrInitialDir = ANGBAND_DIR_XTRA_FONT; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - ofn.lpstrDefExt = "fon"; - - /* Force choice if legal */ - if (GetOpenFileName(&ofn)) - { - /* Force the font */ - if (term_force_font(td, tmp)) - { - /* Access the standard font file */ - path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); - - /* Force the use of that font */ - (void)term_force_font(td, tmp); - } - - /* Assume not bizarre */ - td->bizarre = FALSE; - - /* Reset the tile info */ - td->tile_wid = td->font_wid; - td->tile_hgt = td->font_hgt; - - /* Analyze the font */ - term_getsize(td); - - /* Resize the window */ - term_window_resize(td); - } -#endif - -} - -/* - * Allow the user to lock this window. - */ -static void term_window_pos(term_data *td, HWND hWnd) -{ - SetWindowPos(td->w, hWnd, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -} - -static void windows_map(void); - -/* - * Hack -- redraw a term_data - */ -static void term_data_redraw(term_data *td) -{ - if (td->map_active) - { - /* Redraw the map */ - windows_map(); - } - else - { - /* Activate the term */ - Term_activate(&td->t); - - /* Redraw the contents */ - Term_redraw(); - - /* Restore the term */ - Term_activate(term_screen); - } -} - - -void Term_inversed_area(HWND hWnd, int x, int y, int w, int h) -{ - HDC hdc; - HPEN oldPen; - HBRUSH myBrush, oldBrush; - - term_data *td = (term_data *)GetWindowLong(hWnd, 0); - int tx = td->size_ow1 + x * td->tile_wid; - int ty = td->size_oh1 + y * td->tile_hgt; - int tw = w * td->tile_wid - 1; - int th = h * td->tile_hgt - 1; - - hdc = GetDC(hWnd); - myBrush = CreateSolidBrush(RGB(255, 255, 255)); - oldBrush = SelectObject(hdc, myBrush); - oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); - - PatBlt(hdc, tx, ty, tw, th, PATINVERT); - - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); -} - - - -/*** Function hooks needed by "Term" ***/ - - -#if 0 - -/* - * Initialize a new Term - */ -static void Term_init_win(term *t) -{ - /* XXX Unused */ -} - - -/* - * Nuke an old Term - */ -static void Term_nuke_win(term *t) -{ - /* XXX Unused */ -} - -#endif - - -/*! - * @brief //!< Windows版ユーザ設定項目実装部(実装必須) /Interact with the User - */ -static errr Term_user_win(int n) -{ - /* Unused */ - (void)n; - - /* Success */ - return (0); -} - - -/* - * React to global changes - */ -static errr Term_xtra_win_react(void) -{ - int i; - - /* Simple color */ - if (colors16) - { - /* Save the default colors */ - for (i = 0; i < 256; i++) - { - /* Simply accept the desired colors */ - win_pal[i] = angband_color_table[i][0]; - } - } - - /* Complex color */ - else - { - COLORREF code; - - byte rv, gv, bv; - - bool change = FALSE; - - /* Save the default colors */ - for (i = 0; i < 256; i++) - { - /* Extract desired values */ - rv = angband_color_table[i][1]; - gv = angband_color_table[i][2]; - bv = angband_color_table[i][3]; - - /* Extract a full color code */ - code = PALETTERGB(rv, gv, bv); - - /* Activate changes */ - if (win_clr[i] != code) - { - /* Note the change */ - change = TRUE; - - /* Apply the desired color */ - win_clr[i] = code; - } - } - - /* Activate the palette if needed */ - if (change) (void)new_palette(); - } - - -#ifdef USE_SOUND - - /* Handle "arg_sound" */ - if (use_sound != arg_sound) - { - /* Initialize (if needed) */ - if (arg_sound && !init_sound()) - { - /* Warning */ - plog(_("サウンドを初期化できません!", "Cannot initialize sound!")); - - /* Cannot enable */ - arg_sound = FALSE; - } - - /* Change setting */ - use_sound = arg_sound; - } - -#endif - -#ifdef USE_MUSIC - - /* Handle "arg_sound" */ - if (use_music != arg_music) - { - /* Initialize (if needed) */ - if (arg_music && !init_music()) - { - /* Warning */ - plog(_("BGMを初期化できません!", "Cannot initialize BGM!")); - /* Cannot enable */ - arg_music = FALSE; - } - - /* Change setting */ - use_music = arg_music; - - if(!arg_music) stop_music(); - else select_floor_music(); - - } - -#endif - - -#ifdef USE_GRAPHICS - - /* Handle "arg_graphics" */ - if (use_graphics != arg_graphics) - { - /* Initialize (if needed) */ - if (arg_graphics && !init_graphics()) - { - /* Warning */ - plog(_("グラフィックスを初期化できません!", "Cannot initialize graphics!")); - - /* Cannot enable */ - arg_graphics = GRAPHICS_NONE; - } - - /* Change setting */ - use_graphics = arg_graphics; - - /* Reset visuals */ -#ifdef ANGBAND_2_8_1 - reset_visuals(); -#else /* ANGBAND_2_8_1 */ - reset_visuals(TRUE); -#endif /* ANGBAND_2_8_1 */ - } - -#endif /* USE_GRAPHICS */ - - - /* Clean up windows */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - term *old = Term; - - term_data *td = &data[i]; - - /* Update resized windows */ - if ((td->cols != td->t.wid) || (td->rows != td->t.hgt)) - { - /* Activate */ - Term_activate(&td->t); - - /* Hack -- Resize the term */ - Term_resize(td->cols, td->rows); - - /* Redraw the contents */ - Term_redraw(); - Term_activate(old); - } - } - - - /* Success */ - return (0); -} - - -/* - * Process at least one event - */ -static errr Term_xtra_win_event(int v) -{ - MSG msg; - - /* Wait for an event */ - if (v) - { - /* Block */ - if (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - /* Check for an event */ - else - { - /* Check */ - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - /* Success */ - return 0; -} - - -/* - * Process all pending events - */ -static errr Term_xtra_win_flush(void) -{ - MSG msg; - - /* Process all pending events */ - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Success */ - return (0); -} - - -/* - * Hack -- clear the screen - * - * Make this more efficient - */ -static errr Term_xtra_win_clear(void) -{ - term_data *td = (term_data*)(Term->data); - - HDC hdc; - RECT rc; - - /* Rectangle to erase */ - rc.left = td->size_ow1; - rc.right = rc.left + td->cols * td->tile_wid; - rc.top = td->size_oh1; - rc.bottom = rc.top + td->rows * td->tile_hgt; - - /* Erase it */ - hdc = GetDC(td->w); - SetBkColor(hdc, RGB(0, 0, 0)); - SelectObject(hdc, td->font_id); - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); - - /* bg */ - if (use_bg) - { - rc.left = 0; rc.top = 0; - DrawBG(hdc, &rc); - } - ReleaseDC(td->w, hdc); - - /* Success */ - return 0; -} - - -/* - * Hack -- make a noise - */ -static errr Term_xtra_win_noise(void) -{ - MessageBeep(MB_ICONASTERISK); - return (0); -} - - -/* - * Hack -- make a sound - */ -static errr Term_xtra_win_sound(int v) -{ -#ifdef USE_SOUND - int i; - char buf[1024]; -#endif /* USE_SOUND */ - - /* Sound disabled */ - if (!use_sound) return (1); - - /* Illegal sound */ - if ((v < 0) || (v >= SOUND_MAX)) return (1); - -#ifdef USE_SOUND - - /* Count the samples */ - for (i = 0; i < SAMPLE_MAX; i++) - { - if (!sound_file[v][i]) - break; - } - - /* No sample */ - if (i == 0) return (1); - - /* Build the path */ - path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, sound_file[v][Rand_external(i)]); - -#ifdef WIN32 - - /* Play the sound, catch errors */ - return (PlaySound(buf, 0, SND_FILENAME | SND_ASYNC)); - -#else /* WIN32 */ - - /* Play the sound, catch errors */ - return (sndPlaySound(buf, SND_ASYNC)); - -#endif /* WIN32 */ - -#else /* USE_SOUND */ - - return (1); - -#endif /* USE_SOUND */ -} - -/* - * Hack -- play a music - */ -static errr Term_xtra_win_music(int n, int v) -{ -#ifdef USE_MUSIC - int i = 0; - char buf[1024]; -#endif /* USE_MUSIC */ - - /* Sound disabled */ - - if(!use_music) return (1); - - /* Illegal sound */ - if(n == TERM_XTRA_MUSIC_BASIC && ((v < 0) || (v >= MUSIC_BASIC_MAX))) return (1); - else if(v < 0 || v >= 1000) return(1); /*!< TODO */ - -#ifdef USE_MUSIC - - switch(n) - { - case TERM_XTRA_MUSIC_BASIC: - for (i = 0; i < SAMPLE_MAX; i++) if(!music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_DUNGEON: - for (i = 0; i < SAMPLE_MAX; i++) if(!dungeon_music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_QUEST: - for (i = 0; i < SAMPLE_MAX; i++) if(!quest_music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_TOWN: - for (i = 0; i < SAMPLE_MAX; i++) if(!town_music_file[v][i]) break; - break; - } - - /* No sample */ - if (i == 0) - { - //mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); - //mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); - return (1); - } - - switch(n) - { - case TERM_XTRA_MUSIC_BASIC: - for (i = 0; i < SAMPLE_MAX; i++) if(!music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_DUNGEON: - for (i = 0; i < SAMPLE_MAX; i++) if(!dungeon_music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_QUEST: - for (i = 0; i < SAMPLE_MAX; i++) if(!quest_music_file[v][i]) break; - break; - case TERM_XTRA_MUSIC_TOWN: - for (i = 0; i < SAMPLE_MAX; i++) if(!town_music_file[v][i]) break; - break; - } - - /* No sample */ - if (i == 0) - { - mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); - mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); - return (1); - } - - switch(n) - { - case TERM_XTRA_MUSIC_BASIC: - path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, music_file[v][Rand_external(i)]); - break; - case TERM_XTRA_MUSIC_DUNGEON: - path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, dungeon_music_file[v][Rand_external(i)]); - break; - case TERM_XTRA_MUSIC_QUEST: - path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, quest_music_file[v][Rand_external(i)]); - break; - case TERM_XTRA_MUSIC_TOWN: - path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, town_music_file[v][Rand_external(i)]); - break; - } - - if(current_music_type == n && current_music_id == v) - { - return (0); - } - current_music_type = n; - current_music_id = v; - -#ifdef WIN32 - - mop.lpstrDeviceType = mci_device_type; - mop.lpstrElementName = buf; - mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); - mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); - mciSendCommand(mop.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mop); - mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); - mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop); - return (0); - -#endif /* WIN32 */ - -#else /* USE_MUSIC */ - - return (1); - -#endif /* USE_MUSIC */ - -} - - -/* - * Delay for "x" milliseconds - */ -static int Term_xtra_win_delay(int v) -{ - -#ifdef WIN32 - - /* Sleep */ - Sleep(v); - -#else /* WIN32 */ - - DWORD t; - MSG msg; - - /* Final count */ - t = GetTickCount() + v; - - /* Wait for it */ - while (GetTickCount() < t) - { - /* Handle messages */ - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - -#endif /* WIN32 */ - - /* Success */ - return (0); -} - - -/* - * Do a "special thing" - */ -static errr Term_xtra_win(int n, int v) -{ - /* Handle a subset of the legal requests */ - switch (n) - { - /* Make a bell sound */ - case TERM_XTRA_NOISE: - { - return (Term_xtra_win_noise()); - } - - /* Play a music */ - case TERM_XTRA_MUSIC_BASIC: - case TERM_XTRA_MUSIC_DUNGEON: - case TERM_XTRA_MUSIC_QUEST: - case TERM_XTRA_MUSIC_TOWN: - { - return (Term_xtra_win_music(n, v)); - } - - /* Make a special sound */ - case TERM_XTRA_SOUND: - { - return (Term_xtra_win_sound(v)); - } - - /* Process random events */ - case TERM_XTRA_BORED: - { - return (Term_xtra_win_event(0)); - } - - /* Process an event */ - case TERM_XTRA_EVENT: - { - return (Term_xtra_win_event(v)); - } - - /* Flush all events */ - case TERM_XTRA_FLUSH: - { - return (Term_xtra_win_flush()); - } - - /* Clear the screen */ - case TERM_XTRA_CLEAR: - { - return (Term_xtra_win_clear()); - } - - /* React to global changes */ - case TERM_XTRA_REACT: - { - return (Term_xtra_win_react()); - } - - /* Delay for some milliseconds */ - case TERM_XTRA_DELAY: - { - return (Term_xtra_win_delay(v)); - } - } - - return 1; -} - - - -/* - * Low level graphics (Assumes valid input). - * - * Draw a "cursor" at (x,y), using a "yellow box". - */ -static errr Term_curs_win(int x, int y) -{ - term_data *td = (term_data*)(Term->data); - - RECT rc; - HDC hdc; - - int tile_wid, tile_hgt; - - if (td->map_active) - { - tile_wid = td->map_tile_wid; - tile_hgt = td->map_tile_hgt; - } - else - { - tile_wid = td->tile_wid; - tile_hgt = td->tile_hgt; - } - - /* Frame the grid */ - rc.left = x * tile_wid + td->size_ow1; - rc.right = rc.left + tile_wid; - rc.top = y * tile_hgt + td->size_oh1; - rc.bottom = rc.top + tile_hgt; - - /* Cursor is done as a yellow "box" */ - hdc = GetDC(td->w); - FrameRect(hdc, &rc, hbrYellow); - ReleaseDC(td->w, hdc); - - /* Success */ - return 0; -} - - -/* - * Low level graphics (Assumes valid input). - * - * Draw a "big cursor" at (x,y), using a "yellow box". - */ -static errr Term_bigcurs_win(int x, int y) -{ - term_data *td = (term_data*)(Term->data); - - RECT rc; - HDC hdc; - - int tile_wid, tile_hgt; - - if (td->map_active) - { - /* Normal cursor in map window */ - Term_curs_win(x, y); - return 0; - } - else - { - tile_wid = td->tile_wid; - tile_hgt = td->tile_hgt; - } - - /* Frame the grid */ - rc.left = x * tile_wid + td->size_ow1; - rc.right = rc.left + 2 * tile_wid; - rc.top = y * tile_hgt + td->size_oh1; - rc.bottom = rc.top + tile_hgt; - - /* Cursor is done as a yellow "box" */ - hdc = GetDC(td->w); - FrameRect(hdc, &rc, hbrYellow); - ReleaseDC(td->w, hdc); - - /* Success */ - return 0; -} - - -/* - * Low level graphics (Assumes valid input). - * - * Erase a "block" of "n" characters starting at (x,y). - */ -static errr Term_wipe_win(int x, int y, int n) -{ - term_data *td = (term_data*)(Term->data); - - HDC hdc; - RECT rc; - - /* Rectangle to erase in client coords */ - rc.left = x * td->tile_wid + td->size_ow1; - rc.right = rc.left + n * td->tile_wid; - rc.top = y * td->tile_hgt + td->size_oh1; - rc.bottom = rc.top + td->tile_hgt; - - hdc = GetDC(td->w); - SetBkColor(hdc, RGB(0, 0, 0)); - SelectObject(hdc, td->font_id); - /* bg */ - if (use_bg) - DrawBG(hdc, &rc); - else - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); - ReleaseDC(td->w, hdc); - - /* Success */ - return 0; -} - - -/* - * Low level graphics. Assumes valid input. - * - * Draw several ("n") chars, with an attr, at a given location. - * - * All "graphic" data is handled by "Term_pict_win()", below. - * - * One would think there is a more efficient method for telling a window - * what color it should be using to draw with, but perhaps simply changing - * it every time is not too inefficient. - */ -static errr Term_text_win(int x, int y, int n, TERM_COLOR a, concptr s) -{ - term_data *td = (term_data*)(Term->data); - RECT rc; - HDC hdc; - -#if 1 /* #ifdef JP */ - static HBITMAP WALL; - static HBRUSH myBrush, oldBrush; - static HPEN oldPen; - static bool init_done = FALSE; - - if (!init_done){ - WALL = LoadBitmap(hInstance, AppName); - myBrush = CreatePatternBrush(WALL); - init_done = TRUE; - } -#endif - - /* Total rectangle */ - rc.left = x * td->tile_wid + td->size_ow1; - rc.right = rc.left + n * td->tile_wid; - rc.top = y * td->tile_hgt + td->size_oh1; - rc.bottom = rc.top + td->tile_hgt; - - /* Acquire DC */ - hdc = GetDC(td->w); - - /* Background color */ - SetBkColor(hdc, RGB(0, 0, 0)); - - /* Foreground color */ - if (colors16) - { - SetTextColor(hdc, PALETTEINDEX(win_pal[a])); - } - else if (paletted) - { - SetTextColor(hdc, win_clr[a&0x0F]); - } - else - { - SetTextColor(hdc, win_clr[a]); - } - - /* Use the font */ - SelectObject(hdc, td->font_id); - - /* bg */ - if (use_bg) SetBkMode(hdc, TRANSPARENT); - - /* Bizarre size */ - if (td->bizarre || - (td->tile_hgt != td->font_hgt) || - (td->tile_wid != td->font_wid)) - { - int i; - - /* Erase complete rectangle */ - ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); - - /* bg */ - if (use_bg) DrawBG(hdc, &rc); - - /* New rectangle */ - rc.left += ((td->tile_wid - td->font_wid) / 2); - rc.right = rc.left + td->font_wid; - rc.top += ((td->tile_hgt - td->font_hgt) / 2); - rc.bottom = rc.top + td->font_hgt; - - /* Dump each character */ - for (i = 0; i < n; i++) - { -#ifdef JP - if (use_bigtile && *(s+i)=="■"[0] && *(s+i+1)=="■"[1]) - { - rc.right += td->font_wid; - - oldBrush = SelectObject(hdc, myBrush); - oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); - - /* Dump the wall */ - Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); - - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - rc.right -= td->font_wid; - - /* Advance */ - i++; - rc.left += 2 * td->tile_wid; - rc.right += 2 * td->tile_wid; - } - else if ( iskanji(*(s+i)) ) /* 2バイト文字 */ - { - rc.right += td->font_wid; - /* Dump the text */ - ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, - s+i, 2, NULL); - rc.right -= td->font_wid; - - /* Advance */ - i++; - rc.left += 2 * td->tile_wid; - rc.right += 2 * td->tile_wid; - } else if (*(s+i)==127){ - oldBrush = SelectObject(hdc, myBrush); - oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); - - /* Dump the wall */ - Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); - - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - - /* Advance */ - rc.left += td->tile_wid; - rc.right += td->tile_wid; - } else { - /* Dump the text */ - ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, s+i, 1, NULL); - - /* Advance */ - rc.left += td->tile_wid; - rc.right += td->tile_wid; - } -#else -#if 1 - if (*(s+i)==127){ - oldBrush = SelectObject(hdc, myBrush); - oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); - - /* Dump the wall */ - Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); - - SelectObject(hdc, oldBrush); - SelectObject(hdc, oldPen); - - /* Advance */ - rc.left += td->tile_wid; - rc.right += td->tile_wid; - } else { - /* Dump the text */ - ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, - s+i, 1, NULL); - - /* Advance */ - rc.left += td->tile_wid; - rc.right += td->tile_wid; - } -#else - /* Dump the text */ - ExtTextOut(hdc, rc.left, rc.top, 0, &rc, - s+i, 1, NULL); - - /* Advance */ - rc.left += td->tile_wid; - rc.right += td->tile_wid; -#endif -#endif - - } - } - - /* Normal size */ - else - { - /* Dump the text */ - ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED, &rc, - s, n, NULL); - } - - /* Release DC */ - ReleaseDC(td->w, hdc); - - /* Success */ - return 0; -} - - -/* - * Low level graphics. Assumes valid input. - * - * Draw an array of "special" attr/char pairs at the given location. - * - * We use the "Term_pict_win()" function for "graphic" data, which are - * encoded by setting the "high-bits" of both the "attr" and the "char" - * data. We use the "attr" to represent the "row" of the main bitmap, - * and the "char" to represent the "col" of the main bitmap. The use - * of this function is induced by the "higher_pict" flag. - * - * If "graphics" is not available, we simply "wipe" the given grids. - */ -static errr Term_pict_win(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, concptr cp, const TERM_COLOR *tap, concptr tcp) -{ - term_data *td = (term_data*)(Term->data); - -#ifdef USE_GRAPHICS - - int i; - TERM_LEN x1, y1, w1, h1, tw1, th1; - TERM_LEN x2, y2, w2, h2, tw2 = 0; - TERM_LEN x3, y3; - - HDC hdcMask = NULL; - - HDC hdc; - HDC hdcSrc; - HBITMAP hbmSrcOld; - - /* Paranoia */ - if (!use_graphics) - { - /* Erase the grids */ - return (Term_wipe_win(x, y, n)); - } - - /* Size of bitmap cell */ - w1 = infGraph.CellWidth; - h1 = infGraph.CellHeight; - tw1 = infGraph.TileWidth; - th1 = infGraph.TileHeight; - - /* Size of window cell */ - if (td->map_active) - { - w2 = td->map_tile_wid; - h2 = td->map_tile_hgt; - } - else - { - w2 = td->tile_wid; - h2 = td->tile_hgt; - tw2 = w2; - - /* big tile mode */ - if (use_bigtile) tw2 *= 2; - } - - /* Location of window cell */ - x2 = x * w2 + td->size_ow1 + infGraph.OffsetX; - y2 = y * h2 + td->size_oh1 + infGraph.OffsetY; - - /* Info */ - hdc = GetDC(td->w); - - /* More info */ - hdcSrc = CreateCompatibleDC(hdc); - hbmSrcOld = SelectObject(hdcSrc, infGraph.hBitmap); - - if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) - { - hdcMask = CreateCompatibleDC(hdc); - SelectObject(hdcMask, infMask.hBitmap); - } - - /* Draw attr/char pairs */ - for (i = 0; i < n; i++, x2 += w2) - { - TERM_COLOR a = ap[i]; - char c = cp[i]; - - - /* Extract picture */ - int row = (a & 0x7F); - int col = (c & 0x7F); - - /* Location of bitmap cell */ - x1 = col * w1; - y1 = row * h1; - - if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) - { - x3 = (tcp[i] & 0x7F) * w1; - y3 = (tap[i] & 0x7F) * h1; - tw2 = tw2 * w1 / tw1; - h2 = h2 * h1 / th1; - - /* Perfect size */ - if ((tw1 == tw2) && (th1 == h2)) - { - /* Copy the terrain picture from the bitmap to the window */ - BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, SRCCOPY); - - /* Mask out the tile */ - BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, SRCAND); - - /* Draw the tile */ - BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCPAINT); - } - - /* Need to stretch */ - else - { - /* Set the correct mode for stretching the tiles */ - SetStretchBltMode(hdc, COLORONCOLOR); - - /* Copy the terrain picture from the bitmap to the window */ - StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x3, y3, w1, h1, SRCAND); - - StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, w1, h1, SRCPAINT); - - /* Only draw if terrain and overlay are different */ - if ((x1 != x3) || (y1 != y3)) - { - /* Mask out the tile */ - StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, w1, h1, SRCAND); - - /* Draw the tile */ - StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCPAINT); - } - } - } - else - { - /* Perfect size */ - if ((w1 == tw2) && (h1 == h2)) - { - /* Copy the picture from the bitmap to the window */ - BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCCOPY); - } - - /* Need to stretch */ - else - { - /* Set the correct mode for stretching the tiles */ - SetStretchBltMode(hdc, COLORONCOLOR); - - /* Copy the picture from the bitmap to the window */ - StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCCOPY); - } - } - } - - /* Release */ - SelectObject(hdcSrc, hbmSrcOld); - DeleteDC(hdcSrc); - - if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) - { - /* Release */ - SelectObject(hdcMask, hbmSrcOld); - DeleteDC(hdcMask); - } - - /* Release */ - ReleaseDC(td->w, hdc); - -#else /* USE_GRAPHICS */ - - /* Just erase this grid */ - return (Term_wipe_win(x, y, n)); - -#endif /* USE_GRAPHICS */ - - /* Success */ - return 0; -} - - -static void windows_map(void) -{ - term_data *td = &data[0]; - TERM_COLOR a; - char c; - TERM_LEN x, min_x, max_x; - TERM_LEN y, min_y, max_y; - - TERM_COLOR ta; - char tc; - - /* Only in graphics mode */ - if (!use_graphics) return; - Term_xtra_win_clear(); - - td->map_tile_wid = (td->tile_wid * td->cols) / MAX_WID; - td->map_tile_hgt = (td->tile_hgt * td->rows) / MAX_HGT; - td->map_active = TRUE; - - { - min_x = 0; - min_y = 0; - max_x = cur_wid; - max_y = cur_hgt; - } - - /* Draw the map */ - for (x = min_x; x < max_x; x++) - { - for (y = min_y; y < max_y; y++) - { - map_info(y, x, &a, (char*)&c, &ta, (char*)&tc); - - /* Ignore non-graphics */ - if ((a & 0x80) && (c & 0x80)) - { - Term_pict_win(x - min_x, y - min_y, 1, &a, &c, &ta, &tc); - } - } - } - - /* Hilite the player */ - Term_curs_win(p_ptr->x - min_x, p_ptr->y - min_y); - - /* Wait for a keypress, flush key buffer */ - Term_inkey(&c, TRUE, TRUE); - Term_flush(); - - /* Switch off the map display */ - td->map_active = FALSE; - - /* Restore screen */ - Term_xtra_win_clear(); - Term_redraw(); -} - - -/*** Other routines ***/ - - -/* - * Create and initialize a "term_data" given a title - */ -static void term_data_link(term_data *td) -{ - term *t = &td->t; - - /* Initialize the term */ - term_init(t, td->cols, td->rows, td->keys); - - /* Use a "software" cursor */ - t->soft_cursor = TRUE; - - /* Use "Term_pict" for "graphic" data */ - t->higher_pict = TRUE; - - /* Erase with "white space" */ - t->attr_blank = TERM_WHITE; - t->char_blank = ' '; - -#if 0 - /* Prepare the init/nuke hooks */ - t->init_hook = Term_init_win; - t->nuke_hook = Term_nuke_win; -#endif - - /* Prepare the template hooks */ - t->user_hook = Term_user_win; - t->xtra_hook = Term_xtra_win; - t->curs_hook = Term_curs_win; - t->bigcurs_hook = Term_bigcurs_win; - t->wipe_hook = Term_wipe_win; - t->text_hook = Term_text_win; - t->pict_hook = Term_pict_win; - - /* Remember where we came from */ - t->data = (vptr)(td); -} - - -/* - * Create the windows - * - * First, instantiate the "default" values, then read the "ini_file" - * to over-ride selected values, then create the windows, and fonts. - * - * Must use SW_SHOW not SW_SHOWNA, since on 256 color display - * must make active to realize the palette. - */ -static void init_windows(void) -{ - int i; - - term_data *td; - -#if 0 /* #ifndef JP */ - char buf[1024]; -#endif - - /* Main window */ - td = &data[0]; - WIPE(td, term_data); -#ifdef JP - td->s = "変愚蛮怒"; -#else - td->s = angband_term_name[0]; -#endif - - td->keys = 1024; - td->rows = 24; - td->cols = 80; - td->visible = TRUE; - td->size_ow1 = 2; - td->size_ow2 = 2; - td->size_oh1 = 2; - td->size_oh2 = 2; - td->pos_x = 7 * 30; - td->pos_y = 7 * 20; - td->posfix = FALSE; -#if 1 /* #ifdef JP */ - td->bizarre = TRUE; -#endif - /* Sub windows */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - td = &data[i]; - WIPE(td, term_data); - td->s = angband_term_name[i]; - td->keys = 16; - td->rows = 24; - td->cols = 80; - td->visible = FALSE; - td->size_ow1 = 1; - td->size_ow2 = 1; - td->size_oh1 = 1; - td->size_oh2 = 1; - td->pos_x = (7 - i) * 30; - td->pos_y = (7 - i) * 20; - td->posfix = FALSE; -#if 1 /* #ifdef JP */ - td->bizarre = TRUE; -#endif - } - - - /* Load prefs */ - load_prefs(); - - - /* Main window (need these before term_getsize gets called) */ - td = &data[0]; - td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU | - WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | - WS_VISIBLE); - td->dwExStyle = 0; - td->visible = TRUE; - - /* Sub windows (need these before term_getsize gets called) */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - td = &data[i]; - td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU); - td->dwExStyle = (WS_EX_TOOLWINDOW); - } - - - /* All windows */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - td = &data[i]; - -#if 1 /* #ifdef JP */ - strncpy(td->lf.lfFaceName, td->font_want, LF_FACESIZE); - td->lf.lfCharSet = DEFAULT_CHARSET; - td->lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; - /* Activate the chosen font */ - term_force_font(td, NULL); - if(!td->tile_wid) td->tile_wid = td->font_wid; - if(!td->tile_hgt) td->tile_hgt = td->font_hgt; -#else - /* Access the standard font file */ - path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_FONT, td->font_want); - - /* Activate the chosen font */ - if (term_force_font(td, buf)) - { - /* Access the standard font file */ - path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); - - /* Force the use of that font */ - (void)term_force_font(td, buf); - - td->tile_wid = 8; - td->tile_hgt = 13; - - /* Assume not bizarre */ - td->bizarre = FALSE; - } -#endif - - - /* Analyze the font */ - term_getsize(td); - - /* Resize the window */ - term_window_resize(td); - } - - - /* Sub windows (reverse order) */ - for (i = MAX_TERM_DATA - 1; i >= 1; --i) - { - td = &data[i]; - - my_td = td; - td->w = CreateWindowEx(td->dwExStyle, AngList, - td->s, td->dwStyle, - td->pos_x, td->pos_y, - td->size_wid, td->size_hgt, - HWND_DESKTOP, NULL, hInstance, NULL); - my_td = NULL; - if (!td->w) quit(_("サブウィンドウに作成に失敗しました", "Failed to create sub-window")); - - if (td->visible) - { - td->size_hack = TRUE; - ShowWindow(td->w, SW_SHOW); - td->size_hack = FALSE; - } - - term_data_link(td); - angband_term[i] = &td->t; - - if (td->visible) - { - /* Activate the window */ - SetActiveWindow(td->w); - } - - if (data[i].posfix) - { - term_window_pos(&data[i], HWND_TOPMOST); - } - else - { - term_window_pos(&data[i], td->w); - } - } - - - /* Main window */ - td = &data[0]; - - /* Main window */ - my_td = td; - td->w = CreateWindowEx(td->dwExStyle, AppName, - td->s, td->dwStyle, - td->pos_x, td->pos_y, - td->size_wid, td->size_hgt, - HWND_DESKTOP, NULL, hInstance, NULL); - my_td = NULL; - if (!td->w) quit(_("メインウィンドウの作成に失敗しました", "Failed to create Angband window")); - - term_data_link(td); - angband_term[0] = &td->t; - normsize.x = td->cols; - normsize.y = td->rows; - - /* Activate the main window */ - if (win_maximized) ShowWindow(td->w, SW_SHOWMAXIMIZED); - else ShowWindow(td->w, SW_SHOW); - - /* Bring main window back to top */ - SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - - - /* New palette */ - (void)new_palette(); - - - /* Create a "brush" for drawing the "cursor" */ - hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]); - - - /* Process pending messages */ - (void)Term_xtra_win_flush(); -} - - - -/* - * Prepare the menus - */ -static void setup_menus(void) -{ - int i; - - HMENU hm = GetMenu(data[0].w); - - - /* Menu "File", Disable all */ - EnableMenuItem(hm, IDM_FILE_NEW, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_FILE_OPEN, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_FILE_SAVE, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_FILE_EXIT, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_FILE_SCORE, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - - /* No character available */ - if (!character_generated) - { - /* Menu "File", Item "New" */ - EnableMenuItem(hm, IDM_FILE_NEW, MF_BYCOMMAND | MF_ENABLED); - - /* Menu "File", Item "Open" */ - EnableMenuItem(hm, IDM_FILE_OPEN, MF_BYCOMMAND | MF_ENABLED); - } - - /* A character available */ - if (character_generated) - { - /* Menu "File", Item "Save" */ - EnableMenuItem(hm, IDM_FILE_SAVE, - MF_BYCOMMAND | MF_ENABLED); - } - - /* Menu "File", Item "Exit" */ - EnableMenuItem(hm, IDM_FILE_EXIT, - MF_BYCOMMAND | MF_ENABLED); - - EnableMenuItem(hm, IDM_FILE_SCORE, - MF_BYCOMMAND | MF_ENABLED); - - - /* Menu "Window::Visibility" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i, - (data[i].visible ? MF_CHECKED : MF_UNCHECKED)); - - EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, - MF_BYCOMMAND | MF_ENABLED); - } - - /* Menu "Window::Font" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, - MF_BYCOMMAND | MF_ENABLED); - } - } - - /* Menu "Window::Window Position Fix" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - CheckMenuItem(hm, IDM_WINDOW_POS_0 + i, - (data[i].posfix ? MF_CHECKED : MF_UNCHECKED)); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, - MF_BYCOMMAND | MF_ENABLED); - } - } - - /* Menu "Window::Bizarre Display" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - CheckMenuItem(hm, IDM_WINDOW_BIZ_0 + i, - (data[i].bizarre ? MF_CHECKED : MF_UNCHECKED)); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i, - MF_BYCOMMAND | MF_ENABLED); - - } - } - - /* Menu "Window::Increase Tile Width" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, - MF_BYCOMMAND | MF_ENABLED); - - } - } - - /* Menu "Window::Decrease Tile Width" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, - MF_BYCOMMAND | MF_ENABLED); - - } - } - - /* Menu "Window::Increase Tile Height" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, - MF_BYCOMMAND | MF_ENABLED); - - } - } - - /* Menu "Window::Decrease Tile Height" */ - for (i = 0; i < MAX_TERM_DATA; i++) - { - EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - if (data[i].visible) - { - EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, - MF_BYCOMMAND | MF_ENABLED); - - } - } - - /* Menu "Options", disable all */ - EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - EnableMenuItem(hm, IDM_OPTIONS_SOUND, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); -#ifndef JP - EnableMenuItem(hm, IDM_OPTIONS_SAVER, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); -#endif - - /* Menu "Options", Item "Map" */ - if (use_graphics != GRAPHICS_NONE) - EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP, MF_BYCOMMAND | MF_ENABLED); - else - EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP, - MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - - /* Menu "Options", update all */ - CheckMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, - (arg_graphics == GRAPHICS_NONE ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, - (arg_graphics == GRAPHICS_ORIGINAL ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, - (arg_graphics == GRAPHICS_ADAM_BOLT ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_NEW2_GRAPHICS, - (arg_graphics == GRAPHICS_HENGBAND ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_BIGTILE, - (arg_bigtile ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_MUSIC, - (arg_music ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_SOUND, - (arg_sound ? MF_CHECKED : MF_UNCHECKED)); - CheckMenuItem(hm, IDM_OPTIONS_BG, - (use_bg ? MF_CHECKED : MF_UNCHECKED)); -#ifndef JP - CheckMenuItem(hm, IDM_OPTIONS_SAVER, - (hwndSaver ? MF_CHECKED : MF_UNCHECKED)); -#endif - -#ifdef USE_GRAPHICS - /* Menu "Options", Item "Graphics" */ - EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, MF_ENABLED); - /* Menu "Options", Item "Graphics" */ - EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, MF_ENABLED); - /* Menu "Options", Item "Graphics" */ - EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, MF_ENABLED); - /* Menu "Options", Item "Graphics" */ - EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_ENABLED); -#endif /* USE_GRAPHICS */ - -#ifdef USE_SOUND - /* Menu "Options", Item "Sound" */ - EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_ENABLED); -#endif /* USE_SOUND */ - -#ifdef USE_SAVER - /* Menu "Options", Item "ScreenSaver" */ - EnableMenuItem(hm, IDM_OPTIONS_SAVER, - MF_BYCOMMAND | MF_ENABLED); -#endif /* USE_SAVER */ -} - - -/* - * Check for double clicked (or dragged) savefile - * - * Apparently, Windows copies the entire filename into the first - * piece of the "command line string". Perhaps we should extract - * the "basename" of that filename and append it to the "save" dir. - */ -static void check_for_save_file(LPSTR cmd_line) -{ - char *s; - - /* First arg */ - s = cmd_line; - - /* No args */ - if (!*s) return; - - /* Extract filename */ - strcat(savefile, s); - - /* Validate the file */ - validate_file(savefile); - - /* Game in progress */ - game_in_progress = TRUE; - - /* Play game */ - play_game(FALSE); -} - - -/* - * Process a menu command - */ -static void process_menus(WORD wCmd) -{ - int i; - - term_data *td; - - OPENFILENAME ofn; - - /* Analyze */ - switch (wCmd) - { - /* New game */ - case IDM_FILE_NEW: - { - if (!initialized) - { - plog(_("まだ初期化中です...", "You cannot do that yet...")); - } - else if (game_in_progress) - { - plog(_("プレイ中は新しいゲームを始めることができません!", "You can't start a new game while you're still playing!")); - } - else - { - game_in_progress = TRUE; - Term_flush(); - play_game(TRUE); - quit(NULL); - } - break; - } - - /* Open game */ - case IDM_FILE_OPEN: - { - if (!initialized) - { - plog(_("まだ初期化中です...", "You cannot do that yet...")); - } - else if (game_in_progress) - { - plog(_("プレイ中はゲームをロードすることができません!", "You can't open a new game while you're still playing!")); - } - else - { - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = data[0].w; - ofn.lpstrFilter = "Save Files (*.)\0*\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = savefile; - ofn.nMaxFile = 1024; - ofn.lpstrInitialDir = ANGBAND_DIR_SAVE; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; - - if (GetOpenFileName(&ofn)) - { - /* Load 'savefile' */ - validate_file(savefile); - game_in_progress = TRUE; - Term_flush(); - play_game(FALSE); - quit(NULL); - } - } - break; - } - - /* Save game */ - case IDM_FILE_SAVE: - { - if (game_in_progress && character_generated) - { - /* Paranoia */ - if (!can_save) - { - plog(_("今はセーブすることは出来ません。", "You may not do that right now.")); - break; - } - - /* Hack -- Forget messages */ - msg_flag = FALSE; - - /* Save the game */ -#ifdef ZANGBAND - do_cmd_save_game(FALSE); -#else /* ZANGBAND */ - do_cmd_save_game(); -#endif /* ZANGBAND */ - } - else - { - plog(_("今、セーブすることは出来ません。", "You may not do that right now.")); - } - break; - } - - /* Exit */ - case IDM_FILE_EXIT: - { - if (game_in_progress && character_generated) - { - /* Paranoia */ - if (!can_save) - { - plog(_("今は終了できません。", "You may not do that right now.")); - break; - } - - /* Hack -- Forget messages */ - msg_flag = FALSE; - - forget_lite(); - forget_view(); - clear_mon_lite(); - - /* Save the game */ -#ifdef ZANGBAND - /* do_cmd_save_game(FALSE); */ -#else /* ZANGBAND */ - /* do_cmd_save_game(); */ -#endif /* ZANGBAND */ - Term_key_push(SPECIAL_KEY_QUIT); - break; - } - quit(NULL); - break; - } - - /* Show scores */ - case IDM_FILE_SCORE: - { - char buf[1024]; - - /* Build the filename */ - path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); - - /* Open the binary high score file, for reading */ - highscore_fd = fd_open(buf, O_RDONLY); - - /* Paranoia -- No score file */ - if (highscore_fd < 0) - { - msg_print("Score file unavailable."); - } - else - { - screen_save(); - Term_clear(); - - /* Display the scores */ - display_scores_aux(0, MAX_HISCORES, -1, NULL); - - /* Shut the high score file */ - (void)fd_close(highscore_fd); - - /* Forget the high score fd */ - highscore_fd = -1; - screen_load(); - - /* Hack - Flush it */ - Term_fresh(); - } - - break; - } - - /* Open game */ - case IDM_FILE_MOVIE: - { - if (!initialized) - { - plog(_("まだ初期化中です...", "You cannot do that yet...")); - } - else if (game_in_progress) - { - plog(_("プレイ中はムービーをロードすることができません!", "You can't open a movie while you're playing!")); - } - else - { - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = data[0].w; - ofn.lpstrFilter = "Angband Movie Files (*.amv)\0*.amv\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = savefile; - ofn.nMaxFile = 1024; - ofn.lpstrInitialDir = ANGBAND_DIR_USER; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - - if (GetOpenFileName(&ofn)) - { - /* Load 'savefile' */ - prepare_browse_movie_aux(savefile); - play_game(FALSE); - quit(NULL); - return; - } - } - break; - } - - - case IDM_WINDOW_VIS_0: - { - plog(_("メインウィンドウは非表示にできません!", "You are not allowed to do that!")); - break; - } - - /* Window visibility */ - case IDM_WINDOW_VIS_1: - case IDM_WINDOW_VIS_2: - case IDM_WINDOW_VIS_3: - case IDM_WINDOW_VIS_4: - case IDM_WINDOW_VIS_5: - case IDM_WINDOW_VIS_6: - case IDM_WINDOW_VIS_7: - { - i = wCmd - IDM_WINDOW_VIS_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - if (!td->visible) - { - td->visible = TRUE; - ShowWindow(td->w, SW_SHOW); - term_data_redraw(td); - } - else - { - td->visible = FALSE; - td->posfix = FALSE; - ShowWindow(td->w, SW_HIDE); - } - - break; - } - - /* Window fonts */ - case IDM_WINDOW_FONT_0: - case IDM_WINDOW_FONT_1: - case IDM_WINDOW_FONT_2: - case IDM_WINDOW_FONT_3: - case IDM_WINDOW_FONT_4: - case IDM_WINDOW_FONT_5: - case IDM_WINDOW_FONT_6: - case IDM_WINDOW_FONT_7: - { - i = wCmd - IDM_WINDOW_FONT_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - term_change_font(td); - - break; - } - - /* Window Z Position */ - case IDM_WINDOW_POS_1: - case IDM_WINDOW_POS_2: - case IDM_WINDOW_POS_3: - case IDM_WINDOW_POS_4: - case IDM_WINDOW_POS_5: - case IDM_WINDOW_POS_6: - case IDM_WINDOW_POS_7: - { - i = wCmd - IDM_WINDOW_POS_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - if (!td->posfix && td->visible) - { - td->posfix = TRUE; - term_window_pos(td, HWND_TOPMOST); - } - else - { - td->posfix = FALSE; - term_window_pos(td, data[0].w); - } - - break; - } - - /* Bizarre Display */ - case IDM_WINDOW_BIZ_0: - case IDM_WINDOW_BIZ_1: - case IDM_WINDOW_BIZ_2: - case IDM_WINDOW_BIZ_3: - case IDM_WINDOW_BIZ_4: - case IDM_WINDOW_BIZ_5: - case IDM_WINDOW_BIZ_6: - case IDM_WINDOW_BIZ_7: - { - i = wCmd - IDM_WINDOW_BIZ_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - td->bizarre = !td->bizarre; - - term_getsize(td); - - term_window_resize(td); - - break; - } - - /* Increase Tile Width */ - case IDM_WINDOW_I_WID_0: - case IDM_WINDOW_I_WID_1: - case IDM_WINDOW_I_WID_2: - case IDM_WINDOW_I_WID_3: - case IDM_WINDOW_I_WID_4: - case IDM_WINDOW_I_WID_5: - case IDM_WINDOW_I_WID_6: - case IDM_WINDOW_I_WID_7: - { - i = wCmd - IDM_WINDOW_I_WID_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - td->tile_wid += 1; - - term_getsize(td); - - term_window_resize(td); - - break; - } - - /* Decrease Tile Height */ - case IDM_WINDOW_D_WID_0: - case IDM_WINDOW_D_WID_1: - case IDM_WINDOW_D_WID_2: - case IDM_WINDOW_D_WID_3: - case IDM_WINDOW_D_WID_4: - case IDM_WINDOW_D_WID_5: - case IDM_WINDOW_D_WID_6: - case IDM_WINDOW_D_WID_7: - { - i = wCmd - IDM_WINDOW_D_WID_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - td->tile_wid -= 1; - - term_getsize(td); - - term_window_resize(td); - - break; - } - - /* Increase Tile Height */ - case IDM_WINDOW_I_HGT_0: - case IDM_WINDOW_I_HGT_1: - case IDM_WINDOW_I_HGT_2: - case IDM_WINDOW_I_HGT_3: - case IDM_WINDOW_I_HGT_4: - case IDM_WINDOW_I_HGT_5: - case IDM_WINDOW_I_HGT_6: - case IDM_WINDOW_I_HGT_7: - { - i = wCmd - IDM_WINDOW_I_HGT_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - td->tile_hgt += 1; - - term_getsize(td); - - term_window_resize(td); - - break; - } - - /* Decrease Tile Height */ - case IDM_WINDOW_D_HGT_0: - case IDM_WINDOW_D_HGT_1: - case IDM_WINDOW_D_HGT_2: - case IDM_WINDOW_D_HGT_3: - case IDM_WINDOW_D_HGT_4: - case IDM_WINDOW_D_HGT_5: - case IDM_WINDOW_D_HGT_6: - case IDM_WINDOW_D_HGT_7: - { - i = wCmd - IDM_WINDOW_D_HGT_0; - - if ((i < 0) || (i >= MAX_TERM_DATA)) break; - - td = &data[i]; - - td->tile_hgt -= 1; - - term_getsize(td); - - term_window_resize(td); - - break; - } - - case IDM_OPTIONS_NO_GRAPHICS: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_graphics" */ - if (arg_graphics != GRAPHICS_NONE) - { - arg_graphics = GRAPHICS_NONE; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - } - - break; - } - - case IDM_OPTIONS_OLD_GRAPHICS: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_graphics" */ - if (arg_graphics != GRAPHICS_ORIGINAL) - { - arg_graphics = GRAPHICS_ORIGINAL; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - } - - break; - } - - case IDM_OPTIONS_NEW_GRAPHICS: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_graphics" */ - if (arg_graphics != GRAPHICS_ADAM_BOLT) - { - arg_graphics = GRAPHICS_ADAM_BOLT; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - } - - break; - } - - case IDM_OPTIONS_NEW2_GRAPHICS: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_graphics" */ - if (arg_graphics != GRAPHICS_HENGBAND) - { - arg_graphics = GRAPHICS_HENGBAND; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - } - - break; - } - - case IDM_OPTIONS_BIGTILE: - { - td = &data[0]; - - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_sound" */ - arg_bigtile = !arg_bigtile; - - /* Activate */ - Term_activate(&td->t); - - /* Resize the term */ - Term_resize(td->cols, td->rows); - - /* Redraw later */ - InvalidateRect(td->w, NULL, TRUE); - - break; - } - - case IDM_OPTIONS_MUSIC: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_sound" */ - arg_music = !arg_music; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - - break; - } - - case IDM_OPTIONS_SOUND: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "arg_sound" */ - arg_sound = !arg_sound; - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - - break; - } - - /* bg */ - case IDM_OPTIONS_BG: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - - /* Toggle "use_bg" */ - use_bg = !use_bg; - - init_bg(); - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - - break; - } - - /* bg */ - case IDM_OPTIONS_OPEN_BG: - { - /* Paranoia */ - if (!inkey_flag) - { - plog("You may not do that right now."); - break; - } - else - { - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = data[0].w; - ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = bg_bitmap_file; - ofn.nMaxFile = 1023; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = _("壁紙を選んでね。", "Choose wall paper."); - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if (GetOpenFileName(&ofn)) - { - /* Load 'savefile' */ - use_bg = 1; - init_bg(); - } - - /* React to changes */ - Term_xtra_win_react(); - - /* Hack -- Force redraw */ - Term_key_push(KTRL('R')); - } - break; - } - - case IDM_DUMP_SCREEN_HTML: - { - static char buf[1024] = ""; - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = data[0].w; - ofn.lpstrFilter = "HTML Files (*.html)\0*.html\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = buf; - ofn.nMaxFile = 1023; - ofn.lpstrDefExt = "html"; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = _("HTMLでスクリーンダンプを保存", "Save screen dump as HTML."); - ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; - - if (GetSaveFileName(&ofn)) - { - do_cmd_save_screen_html_aux(buf, 0); - } - break; - } - -#ifdef USE_SAVER - - case IDM_OPTIONS_SAVER: - { - if (hwndSaver) - { - DestroyWindow(hwndSaver); - hwndSaver = NULL; - } - else - { - /* Create a screen scaver window */ - hwndSaver = CreateWindowEx(WS_EX_TOPMOST, "WindowsScreenSaverClass", - "Angband Screensaver", - WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, - 0, 0, GetSystemMetrics(SM_CXSCREEN), - GetSystemMetrics(SM_CYSCREEN), - NULL, NULL, hInstance, NULL); - - if (hwndSaver) - { - /* Push the window to the bottom */ - SetWindowPos(hwndSaver, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } - else - { - plog(_("ウィンドウを作成出来ません", "Failed to create saver window")); - } - } - break; - } - -#endif - - case IDM_OPTIONS_MAP: - { - windows_map(); - break; - } - - case IDM_HELP_CONTENTS: - { -#ifdef HTML_HELP - char tmp[1024]; - path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_HELP, "zangband.chm"); - if (check_file(tmp)) - { - HtmlHelp(data[0].w, tmp, HH_DISPLAY_TOPIC, 0); - } - else - { - plog_fmt(_("ヘルプファイル[%s]が見付かりません。", "Cannot find help file: %s"), tmp); - plog(_("代わりにオンラインヘルプを使用してください。", "Use the online help files instead.")); - } - break; -#else /* HTML_HELP */ - char buf[1024]; - char tmp[1024]; - path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_HELP, "zangband.hlp"); - if (check_file(tmp)) - { - sprintf(buf, "winhelp.exe %s", tmp); - WinExec(buf, SW_NORMAL); - } - else - { - plog_fmt(_("ヘルプファイル[%s]が見付かりません。", "Cannot find help file: %s"), tmp); - plog(_("代わりにオンラインヘルプを使用してください。", "Use the online help files instead.")); - - } - break; -#endif /* HTML_HELP */ - } - } -} - - -static bool process_keydown(WPARAM wParam, LPARAM lParam) -{ - int i; - bool mc = FALSE; - bool ms = FALSE; - bool ma = FALSE; - - /* Extract the modifiers */ - if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE; - if (GetKeyState(VK_SHIFT) & 0x8000) ms = TRUE; - if (GetKeyState(VK_MENU) & 0x8000) ma = TRUE; - - Term_no_press = (ma) ? TRUE : FALSE; - - /* Handle "special" keys */ - if (special_key[(byte)(wParam)] || (ma && !ignore_key[(byte)(wParam)]) ) - { - bool ext_key = (lParam & 0x1000000L) ? TRUE : FALSE; - bool numpad = FALSE; - - /* Begin the macro trigger */ - Term_keypress(31); - - /* Send the modifiers */ - if (mc) Term_keypress('C'); - if (ms) Term_keypress('S'); - if (ma) Term_keypress('A'); - - /* Extract "scan code" */ - i = LOBYTE(HIWORD(lParam)); - - /* Introduce the scan code */ - Term_keypress('x'); - - /* Extended key bit */ - switch (wParam) - { - /* Numpad Enter and '/' are extended key */ - case VK_DIVIDE: - Term_no_press = TRUE; - case VK_RETURN: /* Enter */ - numpad = ext_key; - break; - /* Other extended keys are on full keyboard */ - case VK_NUMPAD0: - case VK_NUMPAD1: - case VK_NUMPAD2: - case VK_NUMPAD3: - case VK_NUMPAD4: - case VK_NUMPAD5: - case VK_NUMPAD6: - case VK_NUMPAD7: - case VK_NUMPAD8: - case VK_NUMPAD9: - case VK_ADD: - case VK_MULTIPLY: - case VK_SUBTRACT: - case VK_SEPARATOR: - case VK_DECIMAL: - Term_no_press = TRUE; - case VK_CLEAR: - case VK_HOME: - case VK_END: - case VK_PRIOR: /* Page Up */ - case VK_NEXT: /* Page Down */ - case VK_INSERT: - case VK_DELETE: - case VK_UP: - case VK_DOWN: - case VK_LEFT: - case VK_RIGHT: - numpad = !ext_key; - } - - /* Special modifiers for keypad keys */ - if (numpad) Term_keypress('K'); - - /* Encode the hexidecimal scan code */ - Term_keypress(hexsym[i/16]); - Term_keypress(hexsym[i%16]); - - /* End the macro trigger */ - Term_keypress(13); - - return 1; - } - - return 0; -} - - -#ifdef __MWERKS__ -LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam); -LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) -#else /* __MWERKS__ */ -LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -#endif /* __MWERKS__ */ -{ - PAINTSTRUCT ps; - HDC hdc; - term_data *td; -#if 0 - MINMAXINFO FAR *lpmmi; - RECT rc; -#endif - int i; - - - /* Acquire proper "term_data" info */ - td = (term_data *)GetWindowLong(hWnd, 0); - - /* Handle message */ - switch (uMsg) - { - case WM_NCCREATE: - { - SetWindowLong(hWnd, 0, (LONG)(my_td)); - break; - } - - case WM_CREATE: - { -#ifdef USE_MUSIC - mop.dwCallback=(DWORD)hWnd; -#endif - return 0; - } - - case WM_GETMINMAXINFO: - { - MINMAXINFO FAR *lpmmi; - RECT rc; - - lpmmi = (MINMAXINFO FAR *)lParam; - - /* this message was sent before WM_NCCREATE */ - if (!td) return 1; - - /* Minimum window size is 80x24 */ - rc.left = rc.top = 0; - rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2; - rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1; - - /* Adjust */ - AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); - - /* Save minimum size */ - lpmmi->ptMinTrackSize.x = rc.right - rc.left; - lpmmi->ptMinTrackSize.y = rc.bottom - rc.top; - - return 0; - } - - case WM_PAINT: - { - BeginPaint(hWnd, &ps); - if (td) term_data_redraw(td); - EndPaint(hWnd, &ps); - ValidateRect(hWnd, NULL); - return 0; - } - -#ifdef USE_MUSIC - case MM_MCINOTIFY: - { - if(wParam == MCI_NOTIFY_SUCCESSFUL) - { - mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); - mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop); - } - return 0; - } -#endif - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - if (process_keydown(wParam, lParam)) - return 0; - break; - } - - case WM_CHAR: - { - if (Term_no_press) Term_no_press = FALSE; - else Term_keypress(wParam); - return 0; - } - - case WM_LBUTTONDOWN: - { - mousex = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1); - mousey = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1); - mouse_down = TRUE; - oldx = mousex; - oldy = mousey; - return 0; - } - - case WM_LBUTTONUP: - { - HGLOBAL hGlobal; - LPSTR lpStr; - int j, sz; - TERM_LEN dx = abs(oldx - mousex) + 1; - TERM_LEN dy = abs(oldy - mousey) + 1; - TERM_LEN ox = (oldx > mousex) ? mousex : oldx; - TERM_LEN oy = (oldy > mousey) ? mousey : oldy; - - mouse_down = FALSE; - paint_rect = FALSE; - -#ifdef JP - sz = (dx + 3) * dy; -#else - sz = (dx + 2) * dy; -#endif - hGlobal = GlobalAlloc(GHND, sz + 1); - if (hGlobal == NULL) return 0; - lpStr = (LPSTR)GlobalLock(hGlobal); - - for (i = 0; i < dy; i++) - { -#ifdef JP - char *s; - char **scr = data[0].t.scr->c; - - C_MAKE(s, (dx + 1), char); - strncpy(s, &scr[oy + i][ox], dx); - - if (ox > 0) - { - if (iskanji(scr[oy + i][ox - 1])) s[0] = ' '; - } - - if (ox + dx < data[0].cols) - { - if (iskanji(scr[oy + i][ox + dx - 1])) s[dx - 1] = ' '; - } - - for (j = 0; j < dx; j++) - { - if (s[j] == 127) s[j] = '#'; - *lpStr++ = s[j]; - } -#else - for (j = 0; j < dx; j++) - { - *lpStr++ = data[0].t.scr->c[oy + i][ox + j]; - } -#endif - if (dy > 1) - { - *lpStr++ = '\r'; - *lpStr++ = '\n'; - } - } - - GlobalUnlock(hGlobal); - if (OpenClipboard(hWnd) == 0) - { - GlobalFree(hGlobal); - return 0; - } - EmptyClipboard(); - SetClipboardData(CF_TEXT, hGlobal); - CloseClipboard(); - - Term_redraw(); - - return 0; - } - - case WM_MOUSEMOVE: - { - if (mouse_down) - { - int dx, dy; - int cx = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1); - int cy = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1); - int ox, oy; - - if (paint_rect) - { - dx = abs(oldx - mousex) + 1; - dy = abs(oldy - mousey) + 1; - ox = (oldx > mousex) ? mousex : oldx; - oy = (oldy > mousey) ? mousey : oldy; - Term_inversed_area(hWnd, ox, oy, dx, dy); - } - else - { - paint_rect = TRUE; - } - - dx = abs(cx - mousex) + 1; - dy = abs(cy - mousey) + 1; - ox = (cx > mousex) ? mousex : cx; - oy = (cy > mousey) ? mousey : cy; - Term_inversed_area(hWnd, ox, oy, dx, dy); - - oldx = cx; - oldy = cy; - } - return 0; - } - - case WM_INITMENU: - { - setup_menus(); - return 0; - } - - case WM_CLOSE: - { - if (game_in_progress && character_generated) - { - if (!can_save) - { - plog(_("今は終了できません。", "You may not do that right now.")); - return 0; - } - - /* Hack -- Forget messages */ - msg_flag = FALSE; - - forget_lite(); - forget_view(); - clear_mon_lite(); - - /* Save the game */ -#ifdef ZANGBAND - /* do_cmd_save_game(FALSE); */ -#else /* ZANGBAND */ - /* do_cmd_save_game(); */ -#endif /* ZANGBAND */ - Term_key_push(SPECIAL_KEY_QUIT); - return 0; - } - quit(NULL); - return 0; - } - - case WM_QUERYENDSESSION: - { - if (game_in_progress && character_generated) - { - /* Hack -- Forget messages */ - msg_flag = FALSE; - - /* Mega-Hack -- Delay death */ - if (p_ptr->chp < 0) p_ptr->is_dead = FALSE; - do_cmd_write_nikki(NIKKI_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----")); - - /* Hardcode panic save */ - p_ptr->panic_save = 1; - - /* Forbid suspend */ - signals_ignore_tstp(); - - /* Indicate panic save */ - (void)strcpy(p_ptr->died_from, _("(緊急セーブ)", "(panic save)")); - - /* Panic save */ - (void)save_player(); - } - quit(NULL); - return 0; - } - - case WM_QUIT: - { - quit(NULL); - return 0; - } - - case WM_COMMAND: - { - process_menus(LOWORD(wParam)); - return 0; - } - - case WM_SIZE: - { - /* this message was sent before WM_NCCREATE */ - if (!td) return 1; - - /* it was sent from inside CreateWindowEx */ - if (!td->w) return 1; - - /* was sent from WM_SIZE */ - if (td->size_hack) return 1; - - switch (wParam) - { - case SIZE_MINIMIZED: - { - /* Hide sub-windows */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - if (data[i].visible) ShowWindow(data[i].w, SW_HIDE); - } - return 0; - } - - case SIZE_MAXIMIZED: - { - /* fall through */ - } - - case SIZE_RESTORED: - { - TERM_LEN cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid; - TERM_LEN rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt; - - /* New size */ - if ((td->cols != cols) || (td->rows != rows)) - { - /* Save the new size */ - td->cols = cols; - td->rows = rows; - - if (!IsZoomed(td->w) && !IsIconic(td->w)) - { - normsize.x = td->cols; - normsize.y = td->rows; - } - - /* Activate */ - Term_activate(&td->t); - - /* Resize the term */ - Term_resize(td->cols, td->rows); - - /* Redraw later */ - InvalidateRect(td->w, NULL, TRUE); - } - - td->size_hack = TRUE; - - /* Show sub-windows */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - if (data[i].visible) ShowWindow(data[i].w, SW_SHOW); - } - - td->size_hack = FALSE; - - return 0; - } - } - break; - } - - case WM_PALETTECHANGED: - { - /* Ignore if palette change caused by itself */ - if ((HWND)wParam == hWnd) return 0; - - /* Fall through... */ - } - - case WM_QUERYNEWPALETTE: - { - if (!paletted) return 0; - - hdc = GetDC(hWnd); - - SelectPalette(hdc, hPal, FALSE); - - i = RealizePalette(hdc); - - /* if any palette entries changed, repaint the window. */ - if (i) InvalidateRect(hWnd, NULL, TRUE); - - ReleaseDC(hWnd, hdc); - - return 0; - } - - case WM_ACTIVATE: - { - if (wParam && !HIWORD(lParam)) - { - /* Do something to sub-windows */ - for (i = 1; i < MAX_TERM_DATA; i++) - { - if (!data[i].posfix) term_window_pos(&data[i], hWnd); - } - - /* Focus on main window */ - SetFocus(hWnd); - - return 0; - } - - break; - } - - case WM_ACTIVATEAPP: - { - if (IsIconic(td->w)) break; - - for (i = 1; i < MAX_TERM_DATA; i++) - { - if(data[i].visible) - { - if (wParam == TRUE) - { - ShowWindow(data[i].w, SW_SHOW); - } - else - { - ShowWindow(data[i].w, SW_HIDE); - } - } - } - } - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - - -#ifdef __MWERKS__ -LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam); -LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) -#else /* __MWERKS__ */ -LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) -#endif /* __MWERKS__ */ -{ - term_data *td; -#if 0 - MINMAXINFO FAR *lpmmi; - RECT rc; -#endif - PAINTSTRUCT ps; - HDC hdc; - int i; - - - /* Acquire proper "term_data" info */ - td = (term_data *)GetWindowLong(hWnd, 0); - - /* Process message */ - switch (uMsg) - { - case WM_NCCREATE: - { - SetWindowLong(hWnd, 0, (LONG)(my_td)); - break; - } - - case WM_CREATE: - { - return 0; - } - - case WM_GETMINMAXINFO: - { - MINMAXINFO FAR *lpmmi; - RECT rc; - - lpmmi = (MINMAXINFO FAR *)lParam; - - /* this message was sent before WM_NCCREATE */ - if (!td) return 1; - - /* Minimum window size is 80x24 */ - rc.left = rc.top = 0; - rc.right = rc.left + 20 * td->tile_wid + td->size_ow1 + td->size_ow2; - rc.bottom = rc.top + 3 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1; - - /* Adjust */ - AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); - - /* Save minimum size */ - lpmmi->ptMinTrackSize.x = rc.right - rc.left; - lpmmi->ptMinTrackSize.y = rc.bottom - rc.top; - - return 0; - } - - case WM_SIZE: - { - TERM_LEN cols; - TERM_LEN rows; - - /* this message was sent before WM_NCCREATE */ - if (!td) return 1; - - /* it was sent from inside CreateWindowEx */ - if (!td->w) return 1; - - /* was sent from inside WM_SIZE */ - if (td->size_hack) return 1; - - td->size_hack = TRUE; - - cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid; - rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt; - - /* New size */ - if ((td->cols != cols) || (td->rows != rows)) - { - /* Save old term */ - term *old_term = Term; - - /* Save the new size */ - td->cols = cols; - td->rows = rows; - - /* Activate */ - Term_activate(&td->t); - - /* Resize the term */ - Term_resize(td->cols, td->rows); - - /* Activate */ - Term_activate(old_term); - - /* Redraw later */ - InvalidateRect(td->w, NULL, TRUE); - - /* HACK - Redraw all windows */ - p_ptr->window = 0xFFFFFFFF; - handle_stuff(); - } - - td->size_hack = FALSE; - - return 0; - } - - case WM_PAINT: - { - BeginPaint(hWnd, &ps); - if (td) term_data_redraw(td); - EndPaint(hWnd, &ps); - return 0; - } - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - if (process_keydown(wParam, lParam)) - return 0; - break; - } - - case WM_CHAR: - { - if (Term_no_press) Term_no_press = FALSE; - else Term_keypress(wParam); - return 0; - } - - case WM_PALETTECHANGED: - { - /* ignore if palette change caused by itself */ - if ((HWND)wParam == hWnd) return FALSE; - /* otherwise, fall through!!! */ - } - - case WM_QUERYNEWPALETTE: - { - if (!paletted) return 0; - hdc = GetDC(hWnd); - SelectPalette(hdc, hPal, FALSE); - i = RealizePalette(hdc); - /* if any palette entries changed, repaint the window. */ - if (i) InvalidateRect(hWnd, NULL, TRUE); - ReleaseDC(hWnd, hdc); - return 0; - } - - case WM_NCLBUTTONDOWN: - { - -#ifdef HTCLOSE - if (wParam == HTCLOSE) wParam = HTSYSMENU; -#endif /* HTCLOSE */ - - if (wParam == HTSYSMENU) - { - if (td->visible) - { - td->visible = FALSE; - ShowWindow(td->w, SW_HIDE); - } - - return 0; - } - - break; - } - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - - -#ifdef USE_SAVER - -#define MOUSE_SENS 40 - -#ifdef __MWERKS__ -LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam); -LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) -#else /* __MWERKS__ */ -LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, - WPARAM wParam, LPARAM lParam) -#endif /* __MWERKS__ */ -{ - static int iMouse = 0; - static WORD xMouse = 0; - static WORD yMouse = 0; - - int dx, dy; - - - /* Process */ - switch (uMsg) - { - case WM_NCCREATE: - { - break; - } - - case WM_SETCURSOR: - { - SetCursor(NULL); - return 0; - } - -#if 0 - case WM_ACTIVATE: - { - if (LOWORD(wParam) == WA_INACTIVE) break; - - /* else fall through */ - } -#endif - - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_KEYDOWN: - { - SendMessage(hWnd, WM_CLOSE, 0, 0); - return 0; - } - - case WM_MOUSEMOVE: - { - if (iMouse) - { - dx = LOWORD(lParam) - xMouse; - dy = HIWORD(lParam) - yMouse; - - if (dx < 0) dx = -dx; - if (dy < 0) dy = -dy; - - if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS)) - { - SendMessage(hWnd, WM_CLOSE, 0, 0); - } - } - - /* Save last location */ - iMouse = 1; - xMouse = LOWORD(lParam); - yMouse = HIWORD(lParam); - - return 0; - } - - case WM_CLOSE: - { - DestroyWindow(hwndSaver); - hwndSaver = NULL; - return 0; - } - } - - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -#endif /* USE_SAVER */ - - - - - -/*** Temporary Hooks ***/ - - -/* - * Display warning message (see "z-util.c") - */ -static void hack_plog(concptr str) -{ - /* Give a warning */ - if (str) - { -#ifdef JP - MessageBox(NULL, str, "警告!", - MB_ICONEXCLAMATION | MB_OK); -#else - MessageBox(NULL, str, "Warning", - MB_ICONEXCLAMATION | MB_OK); -#endif - - } -} - - -/* - * Display error message and quit (see "z-util.c") - */ -static void hack_quit(concptr str) -{ - /* Give a warning */ - if (str) - { -#ifdef JP - MessageBox(NULL, str, "エラー!", - MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); -#else - MessageBox(NULL, str, "Error", - MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); -#endif - - } - - /* Unregister the classes */ - UnregisterClass(AppName, hInstance); - - /* Destroy the icon */ - if (hIcon) DestroyIcon(hIcon); - - /* Exit */ - exit(0); -} - - - -/*** Various hooks ***/ - - -/* - * Display warning message (see "z-util.c") - */ -static void hook_plog(concptr str) -{ - /* Warning */ - if (str) - { -#ifdef JP - MessageBox(data[0].w, str, "警告!", - MB_ICONEXCLAMATION | MB_OK); -#else - MessageBox(data[0].w, str, "Warning", - MB_ICONEXCLAMATION | MB_OK); -#endif - - } -} - - -/* - * Display error message and quit (see "z-util.c") - */ -static void hook_quit(concptr str) -{ - int i; - - - /* Give a warning */ - if (str) - { -#ifdef JP - MessageBox(data[0].w, str, "エラー!", - MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); -#else - MessageBox(data[0].w, str, "Error", - MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); -#endif - - } - - - /* Save the preferences */ - save_prefs(); - - - /*** Could use 'Term_nuke_win()' */ - - /* Destroy all windows */ - for (i = MAX_TERM_DATA - 1; i >= 0; --i) - { - term_force_font(&data[i], NULL); - if (data[i].font_want) string_free(data[i].font_want); - if (data[i].w) DestroyWindow(data[i].w); - data[i].w = 0; - } - - /* Free the bitmap stuff */ -#ifdef USE_GRAPHICS - if (infGraph.hPalette) DeleteObject(infGraph.hPalette); - if (infGraph.hBitmap) DeleteObject(infGraph.hBitmap); - - if (infMask.hPalette) DeleteObject(infMask.hPalette); - if (infMask.hBitmap) DeleteObject(infMask.hBitmap); - -#endif /* USE_GRAPHICS */ - - /*** Free some other stuff ***/ - - DeleteObject(hbrYellow); - - /* bg */ - delete_bg(); - - if (hPal) DeleteObject(hPal); - - UnregisterClass(AppName, hInstance); - - if (hIcon) DestroyIcon(hIcon); - - exit(0); -} - - - -/*** Initialize ***/ - - -/* - * Init some stuff - */ -static void init_stuff(void) -{ - int i; - - char path[1024]; - - - /* Get program name with full path */ - GetModuleFileName(hInstance, path, 512); - - /* Save the "program name" */ - argv0 = path; - - /* Get the name of the "*.ini" file */ - strcpy(path + strlen(path) - 4, ".INI"); - - /* Save the the name of the ini-file */ - ini_file = string_make(path); - - /* Analyze the path */ - i = strlen(path); - - /* Get the path */ - for (; i > 0; i--) - { - if (path[i] == '\\') - { - /* End of path */ - break; - } - } - - /* Add "lib" to the path */ - strcpy(path + i + 1, "lib\\"); - - /* Validate the path */ - validate_dir(path, TRUE); - - /* Init the file paths */ - init_file_paths(path); - - /* Hack -- Validate the paths */ - validate_dir(ANGBAND_DIR_APEX, FALSE); - validate_dir(ANGBAND_DIR_BONE, FALSE); - - /* Allow missing 'edit' directory */ - if (!check_dir(ANGBAND_DIR_EDIT)) - { - /* Must have 'data'! */ - validate_dir(ANGBAND_DIR_DATA, TRUE); - } - else - { - /* Don't need 'data' */ - validate_dir(ANGBAND_DIR_DATA, FALSE); - } - - validate_dir(ANGBAND_DIR_FILE, TRUE); - validate_dir(ANGBAND_DIR_HELP, FALSE); - validate_dir(ANGBAND_DIR_INFO, FALSE); - validate_dir(ANGBAND_DIR_PREF, TRUE); - validate_dir(ANGBAND_DIR_SAVE, FALSE); - validate_dir(ANGBAND_DIR_USER, TRUE); - validate_dir(ANGBAND_DIR_XTRA, TRUE); - - /* Build the filename */ - path_build(path, sizeof(path), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt")); - - /* Hack -- Validate the "news.txt" file */ - validate_file(path); - - -#if 0 /* #ifndef JP */ - /* Build the "font" path */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "font"); - - /* Allocate the path */ - ANGBAND_DIR_XTRA_FONT = string_make(path); - - /* Validate the "font" directory */ - validate_dir(ANGBAND_DIR_XTRA_FONT, TRUE); - - /* Build the filename */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); - - /* Hack -- Validate the basic font */ - validate_file(path); -#endif - - -#ifdef USE_GRAPHICS - - /* Build the "graf" path */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "graf"); - - /* Allocate the path */ - ANGBAND_DIR_XTRA_GRAF = string_make(path); - - /* Validate the "graf" directory */ - validate_dir(ANGBAND_DIR_XTRA_GRAF, TRUE); - -#endif /* USE_GRAPHICS */ - - -#ifdef USE_SOUND - - /* Build the "sound" path */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound"); - - /* Allocate the path */ - ANGBAND_DIR_XTRA_SOUND = string_make(path); - - /* Validate the "sound" directory */ - validate_dir(ANGBAND_DIR_XTRA_SOUND, FALSE); - -#endif /* USE_SOUND */ - -#ifdef USE_MUSIC - - /* Build the "music" path */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "music"); - - /* Allocate the path */ - ANGBAND_DIR_XTRA_MUSIC = string_make(path); - - /* Validate the "music" directory */ - validate_dir(ANGBAND_DIR_XTRA_MUSIC, FALSE); - -#endif /* USE_MUSIC */ - - /* Build the "help" path */ - path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "help"); - - /* Allocate the path */ - ANGBAND_DIR_XTRA_HELP = string_make(path); - - /* Validate the "help" directory */ - /* validate_dir(ANGBAND_DIR_XTRA_HELP); */ -} - -/*! - * @brief (Windows固有)変愚蛮怒が起動済かどうかのチェック - */ -static bool is_already_running(void) -{ - bool result = FALSE; - HANDLE hMutex; - - hMutex = CreateMutex(NULL, TRUE, VERSION_NAME); - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - result = TRUE; - } - return result; -} - - -/*! - * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント - */ -int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, - LPSTR lpCmdLine, int nCmdShow) -{ - int i; - - WNDCLASS wc; - HDC hdc; - MSG msg; - - setlocale(LC_ALL, "ja_JP.utf8"); - - /* Unused */ - (void)nCmdShow; - - /* Save globally */ - hInstance = hInst; - - - /* Prevent multiple run */ - if (is_already_running()) - { - MessageBox(NULL, - _("変愚蛮怒はすでに起動しています。", "Hengband is already running."), - _("エラー!", "Error") , - MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); - return FALSE; - } - - if (hPrevInst == NULL) - { - wc.style = CS_CLASSDC; - wc.lpfnWndProc = AngbandWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 4; /* one long pointer to term_data */ - wc.hInstance = hInst; - wc.hIcon = hIcon = LoadIcon(hInst, AppName); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = GetStockObject(BLACK_BRUSH); - wc.lpszMenuName = AppName; - wc.lpszClassName = AppName; - - if (!RegisterClass(&wc)) exit(1); - - wc.lpfnWndProc = AngbandListProc; - wc.lpszMenuName = NULL; - wc.lpszClassName = AngList; - - if (!RegisterClass(&wc)) exit(2); - -#ifdef USE_SAVER - - wc.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS; - wc.lpfnWndProc = AngbandSaverProc; - wc.hCursor = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = "WindowsScreenSaverClass"; - - if (!RegisterClass(&wc)) exit(3); - -#endif - - } - - /* Temporary hooks */ - plog_aux = hack_plog; - quit_aux = hack_quit; - core_aux = hack_quit; - - /* Prepare the filepaths */ - init_stuff(); - - /* Initialize the keypress analyzer */ - for (i = 0; special_key_list[i]; ++i) - { - special_key[special_key_list[i]] = TRUE; - } - /* Initialize the keypress analyzer */ - for (i = 0; ignore_key_list[i]; ++i) - { - ignore_key[ignore_key_list[i]] = TRUE; - } - - /* Determine if display is 16/256/true color */ - hdc = GetDC(NULL); - colors16 = (GetDeviceCaps(hdc, BITSPIXEL) == 4); - paletted = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? TRUE : FALSE); - ReleaseDC(NULL, hdc); - - /* Initialize the colors */ - for (i = 0; i < 256; i++) - { - byte rv, gv, bv; - - /* Extract desired values */ - rv = angband_color_table[i][1]; - gv = angband_color_table[i][2]; - bv = angband_color_table[i][3]; - - /* Extract the "complex" code */ - win_clr[i] = PALETTERGB(rv, gv, bv); - - /* Save the "simple" code */ - angband_color_table[i][0] = win_pal[i]; - } - - /* Prepare the windows */ - init_windows(); - - /* bg */ - init_bg(); - - /* Activate hooks */ - plog_aux = hook_plog; - quit_aux = hook_quit; - core_aux = hook_quit; - - /* Set the system suffix */ - ANGBAND_SYS = "win"; - - /* Set the keyboard suffix */ - if (7 != GetKeyboardType(0)) - ANGBAND_KEYBOARD = "0"; - else - { - /* Japanese keyboard */ - switch (GetKeyboardType(1)) - { - case 0x0D01: case 0x0D02: - case 0x0D03: case 0x0D04: - case 0x0D05: case 0x0D06: - /* NEC PC-98x1 */ - ANGBAND_KEYBOARD = "NEC98"; - break; - default: - /* PC/AT */ - ANGBAND_KEYBOARD = "JAPAN"; - } - } - - /* Catch nasty signals */ - signals_init(); - - Term_activate(term_screen); - init_angband(); - - /* We are now initialized */ - initialized = TRUE; -#ifdef CHUUKEI - if(lpCmdLine[0] == '-'){ - switch(lpCmdLine[1]) - { - case 'p': - case 'P': - { - if (!lpCmdLine[2]) break; - chuukei_server = TRUE; - if(connect_chuukei_server(&lpCmdLine[2])<0){ - msg_print("connect fail"); - return 0; - } - msg_print("connect"); - msg_print(NULL); - break; - } - - case 'c': - case 'C': - { - if (!lpCmdLine[2]) break; - chuukei_client = TRUE; - connect_chuukei_server(&lpCmdLine[2]); - play_game(FALSE); - quit(NULL); - return 0; - } - case 'X': - case 'x': - { - if (!lpCmdLine[2]) break; - prepare_browse_movie(&lpCmdLine[2]); - play_game(FALSE); - quit(NULL); - return 0; - } - } - } -#endif - -#ifdef CHUUKEI - /* Did the user double click on a save file? */ - if(!chuukei_server) check_for_save_file(lpCmdLine); -#else - /* Did the user double click on a save file? */ - check_for_save_file(lpCmdLine); -#endif - - /* Prompt the user */ - prt(_("[ファイル] メニューの [新規] または [開く] を選択してください。", "[Choose 'New' or 'Open' from the 'File' menu]"), 23, _(8, 17)); - - Term_fresh(); - - /* Process messages forever */ - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Paranoia */ - quit(NULL); - - /* Paranoia */ - return (0); -} - - -#endif /* WINDOWS */ - +/*! +* @file main-win.c +* @brief Windows版固有実装(メインエントリポイント含む) +* @date 2018/03/16 +* @author Hengband Team +* @detail +* +*

概要

+* Windows98かその前後の頃を起点としたAPI実装。 +* 各種のゲームエンジンは無論、 +* DirectXといった昨今描画に標準的となったライブラリも用いていない。 +* タイルの描画処理などについては、現在動作の詳細を検証中。 +* +*

フォーク元の概要

+*

+* Copyright (c) 1997 Ben Harrison, Skirmantas Kligys, and others +* +* This software may be copied and distributed for educational, research, +* and not for profit purposes provided that this copyright and statement +* are included in all such copies. +*

+*

+* This file helps Angband work with Windows computers. +* +* To use this file, use an appropriate "Makefile" or "Project File", +* make sure that "WINDOWS" and/or "WIN32" are defined somewhere, and +* make sure to obtain various extra files as described below. +* +* The official compilation uses the CodeWarrior Pro compiler, which +* includes a special project file and precompilable header file. +*

+* +*

+* See also "main-dos.c" and "main-ibm.c". +*

+* +*

+* The "lib/user/pref-win.prf" file contains keymaps, macro definitions, +* and/or color redefinitions. +*

+* +*

+* The "lib/user/font-win.prf" contains attr/char mappings for use with the +* normal "lib/xtra/font/*.fon" font files. +*

+* +*

+* The "lib/user/graf-win.prf" contains attr/char mappings for use with the +* special "lib/xtra/graf/*.bmp" bitmap files, which are activated by a menu +* item. +*

+* +*

+* Compiling this file, and using the resulting executable, requires +* several extra files not distributed with the standard Angband code. +* If "USE_GRAPHICS" is defined, then "readdib.h" and "readdib.c" must +* be placed into "src/", and the "8X8.BMP" bitmap file must be placed +* into "lib/xtra/graf". In any case, some "*.fon" files (including +* "8X13.FON" if nothing else) must be placed into "lib/xtra/font/". +* If "USE_SOUND" is defined, then some special library (for example, +* "winmm.lib") may need to be linked in, and desired "*.WAV" sound +* files must be placed into "lib/xtra/sound/". All of these extra +* files can be found in the "ext-win" archive. +*

+* +*

+* The "Term_xtra_win_clear()" function should probably do a low-level +* clear of the current window, and redraw the borders and other things, +* if only for efficiency. +*

+* +*

+* A simpler method is needed for selecting the "tile size" for windows. +*

+* +*

+* The various "warning" messages assume the existance of the "screen.w" +* window, I think, and only a few calls actually check for its existance, +* this may be okay since "NULL" means "on top of all windows". (?) The +* user must never be allowed to "hide" the main window, or the "menubar" +* will disappear. +*

+* +*

+* Special "Windows Help Files" can be placed into "lib/xtra/help/" for +* use with the "winhelp.exe" program. These files *may* be available +* at the ftp site somewhere, but I have not seen them. +*

+* +*

+* Initial framework (and most code) by Ben Harrison (benh@phial.com). +* +* Original code by Skirmantas Kligys (kligys@scf.usc.edu). +* +* Additional code by Ross E Becker (beckerr@cis.ohio-state.edu), +* and Chris R. Martin (crm7479@tam2000.tamu.edu). +*

+*/ + +#include "angband.h" + +#ifdef WINDOWS +#include +#include +#include +#include "z-term.h" + +/* + * Extract the "WIN32" flag from the compiler + */ +#if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__) +# ifndef WIN32 +# define WIN32 +# endif +#endif + + +/* + * Hack -- allow use of "screen saver" mode + */ +#define USE_SAVER + + +/* + * Menu constants -- see "ANGBAND.RC" + */ + +#define IDM_FILE_NEW 100 +#define IDM_FILE_OPEN 101 +#define IDM_FILE_SAVE 110 +#define IDM_FILE_SCORE 120 +#define IDM_FILE_MOVIE 121 +#define IDM_FILE_EXIT 130 + +#define IDM_WINDOW_VIS_0 200 +#define IDM_WINDOW_VIS_1 201 +#define IDM_WINDOW_VIS_2 202 +#define IDM_WINDOW_VIS_3 203 +#define IDM_WINDOW_VIS_4 204 +#define IDM_WINDOW_VIS_5 205 +#define IDM_WINDOW_VIS_6 206 +#define IDM_WINDOW_VIS_7 207 + +#define IDM_WINDOW_FONT_0 210 +#define IDM_WINDOW_FONT_1 211 +#define IDM_WINDOW_FONT_2 212 +#define IDM_WINDOW_FONT_3 213 +#define IDM_WINDOW_FONT_4 214 +#define IDM_WINDOW_FONT_5 215 +#define IDM_WINDOW_FONT_6 216 +#define IDM_WINDOW_FONT_7 217 + +#define IDM_WINDOW_POS_0 220 +#define IDM_WINDOW_POS_1 221 +#define IDM_WINDOW_POS_2 222 +#define IDM_WINDOW_POS_3 223 +#define IDM_WINDOW_POS_4 224 +#define IDM_WINDOW_POS_5 225 +#define IDM_WINDOW_POS_6 226 +#define IDM_WINDOW_POS_7 227 + +#define IDM_WINDOW_BIZ_0 230 +#define IDM_WINDOW_BIZ_1 231 +#define IDM_WINDOW_BIZ_2 232 +#define IDM_WINDOW_BIZ_3 233 +#define IDM_WINDOW_BIZ_4 234 +#define IDM_WINDOW_BIZ_5 235 +#define IDM_WINDOW_BIZ_6 236 +#define IDM_WINDOW_BIZ_7 237 + +#define IDM_WINDOW_I_WID_0 240 +#define IDM_WINDOW_I_WID_1 241 +#define IDM_WINDOW_I_WID_2 242 +#define IDM_WINDOW_I_WID_3 243 +#define IDM_WINDOW_I_WID_4 244 +#define IDM_WINDOW_I_WID_5 245 +#define IDM_WINDOW_I_WID_6 246 +#define IDM_WINDOW_I_WID_7 247 + +#define IDM_WINDOW_D_WID_0 250 +#define IDM_WINDOW_D_WID_1 251 +#define IDM_WINDOW_D_WID_2 252 +#define IDM_WINDOW_D_WID_3 253 +#define IDM_WINDOW_D_WID_4 254 +#define IDM_WINDOW_D_WID_5 255 +#define IDM_WINDOW_D_WID_6 256 +#define IDM_WINDOW_D_WID_7 257 + +#define IDM_WINDOW_I_HGT_0 260 +#define IDM_WINDOW_I_HGT_1 261 +#define IDM_WINDOW_I_HGT_2 262 +#define IDM_WINDOW_I_HGT_3 263 +#define IDM_WINDOW_I_HGT_4 264 +#define IDM_WINDOW_I_HGT_5 265 +#define IDM_WINDOW_I_HGT_6 266 +#define IDM_WINDOW_I_HGT_7 267 + +#define IDM_WINDOW_D_HGT_0 270 +#define IDM_WINDOW_D_HGT_1 271 +#define IDM_WINDOW_D_HGT_2 272 +#define IDM_WINDOW_D_HGT_3 273 +#define IDM_WINDOW_D_HGT_4 274 +#define IDM_WINDOW_D_HGT_5 275 +#define IDM_WINDOW_D_HGT_6 276 +#define IDM_WINDOW_D_HGT_7 277 + +#define IDM_OPTIONS_NO_GRAPHICS 400 +#define IDM_OPTIONS_OLD_GRAPHICS 401 +#define IDM_OPTIONS_NEW_GRAPHICS 402 +#define IDM_OPTIONS_NEW2_GRAPHICS 403 +#define IDM_OPTIONS_BIGTILE 409 +#define IDM_OPTIONS_SOUND 410 +#define IDM_OPTIONS_MUSIC 411 +#define IDM_OPTIONS_SAVER 420 +#define IDM_OPTIONS_MAP 430 +#define IDM_OPTIONS_BG 440 +#define IDM_OPTIONS_OPEN_BG 441 + +#define IDM_DUMP_SCREEN_HTML 450 + +#define IDM_HELP_CONTENTS 901 + +/* + * Exclude parts of WINDOWS.H that are not needed + */ +#define NOCOMM /* Comm driver APIs and definitions */ +#define NOLOGERROR /* LogError() and related definitions */ +#define NOPROFILER /* Profiler APIs */ +#define NOLFILEIO /* _l* file I/O routines */ +#define NOOPENFILE /* OpenFile and related definitions */ +#define NORESOURCE /* Resource management */ +#define NOATOM /* Atom management */ +#define NOLANGUAGE /* Character test routines */ +#define NOLSTRING /* lstr* string management routines */ +#define NODBCS /* Double-byte character set routines */ +#define NOKEYBOARDINFO /* Keyboard driver routines */ +#define NOCOLOR /* COLOR_* color values */ +#define NODRAWTEXT /* DrawText() and related definitions */ +#define NOSCALABLEFONT /* Truetype scalable font support */ +#define NOMETAFILE /* Metafile support */ +#define NOSYSTEMPARAMSINFO /* SystemParametersInfo() and SPI_* definitions */ +#define NODEFERWINDOWPOS /* DeferWindowPos and related definitions */ +#define NOKEYSTATES /* MK_* message key state flags */ +#define NOWH /* SetWindowsHook and related WH_* definitions */ +#define NOCLIPBOARD /* Clipboard APIs and definitions */ +#define NOICONS /* IDI_* icon IDs */ +#define NOMDI /* MDI support */ +#define NOHELP /* Help support */ + +/* Not defined since it breaks Borland C++ 5.5 */ +/* #define NOCTLMGR */ /* Control management and controls */ + +/* + * Exclude parts of WINDOWS.H that are not needed (Win32) + */ +#define WIN32_LEAN_AND_MEAN +#define NONLS /* All NLS defines and routines */ +#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */ +#define NOKANJI /* Kanji support stuff. */ +#define NOMCX /* Modem Configuration Extensions */ + +/* + * Include the "windows" support file + */ +#include + +/* + * Exclude parts of MMSYSTEM.H that are not needed + */ +#define MMNODRV /* Installable driver support */ +#define MMNOWAVE /* Waveform support */ +#define MMNOMIDI /* MIDI support */ +#define MMNOAUX /* Auxiliary audio support */ +#define MMNOTIMER /* Timer support */ +#define MMNOJOY /* Joystick support */ +#define MMNOMCI /* MCI support */ +#define MMNOMMIO /* Multimedia file I/O support */ +#define MMNOMMSYSTEM /* General MMSYSTEM functions */ + +/* + * Include some more files. Note: the Cygnus Cygwin compiler + * doesn't use mmsystem.h instead it includes the winmm library + * which performs a similar function. + */ +#include +#include + +/* + * HTML-Help requires htmlhelp.h and htmlhelp.lib from Microsoft's + * HTML Workshop < http://msdn.microsoft.com/workshop/author/htmlhelp/ >. + */ +/* #define HTML_HELP */ + +#ifdef HTML_HELP +#include +#endif /* HTML_HELP */ + +/* + * Include the support for loading bitmaps + */ +#ifdef USE_GRAPHICS +# include "readdib.h" +#endif + +/* + * Hack -- Fake declarations from "dos.h" + */ +#ifdef WIN32 +#define INVALID_FILE_NAME (DWORD)0xFFFFFFFF +#else /* WIN32 */ +#define FA_LABEL 0x08 /* Volume label */ +#define FA_DIREC 0x10 /* Directory */ +unsigned _cdecl _dos_getfileattr(concptr , unsigned *); +#endif /* WIN32 */ + +/* + * Silliness in WIN32 drawing routine + */ +#ifdef WIN32 +# define MoveTo(H,X,Y) MoveToEx(H, X, Y, NULL) +#endif /* WIN32 */ + +/* + * Silliness for Windows 95 + */ +#ifndef WS_EX_TOOLWINDOW +# define WS_EX_TOOLWINDOW 0 +#endif + +/* + * Foreground color bits (hard-coded by DOS) + */ +#define VID_BLACK 0x00 +#define VID_BLUE 0x01 +#define VID_GREEN 0x02 +#define VID_CYAN 0x03 +#define VID_RED 0x04 +#define VID_MAGENTA 0x05 +#define VID_YELLOW 0x06 +#define VID_WHITE 0x07 + +/* + * Bright text (hard-coded by DOS) + */ +#define VID_BRIGHT 0x08 + +/* + * Background color bits (hard-coded by DOS) + */ +#define VUD_BLACK 0x00 +#define VUD_BLUE 0x10 +#define VUD_GREEN 0x20 +#define VUD_CYAN 0x30 +#define VUD_RED 0x40 +#define VUD_MAGENTA 0x50 +#define VUD_YELLOW 0x60 +#define VUD_WHITE 0x70 + +/* + * Blinking text (hard-coded by DOS) + */ +#define VUD_BRIGHT 0x80 + + +/* + * Forward declare + */ +typedef struct _term_data term_data; + +/*! + * @struct _term_data + * @brief ターム情報構造体 / Extra "term" data + * @details + *

+ * pos_x / pos_y は各タームの左上点座標を指す。 + *

+ *

+ * tile_wid / tile_hgt は[ウィンドウ]メニューのタイルの幅/高さを~を + * 1ドットずつ調整するステータスを指す。 + * また、フォントを変更すると都度自動調整される。 + *

+ *

+ * Note the use of "font_want" for the names of the font file requested by + * the user, and the use of "font_file" for the currently active font file. + * + * The "font_file" is uppercased, and takes the form "8X13.FON", while + * "font_want" can be in almost any form as long as it could be construed + * as attempting to represent the name of a font. + *

+ */ +struct _term_data +{ + term t; + concptr s; + HWND w; + DWORD dwStyle; + DWORD dwExStyle; + + uint keys; + TERM_LEN rows; /* int -> uint */ + TERM_LEN cols; + + uint pos_x; //!< タームの左上X座標 + uint pos_y; //!< タームの左上Y座標 + uint size_wid; + uint size_hgt; + uint size_ow1; + uint size_oh1; + uint size_ow2; + uint size_oh2; + + bool size_hack; + bool xtra_hack; + bool visible; + bool bizarre; + concptr font_want; + concptr font_file; + HFONT font_id; + int font_wid; //!< フォント横幅 + int font_hgt; //!< フォント縦幅 + int tile_wid; //!< タイル横幅 + int tile_hgt; //!< タイル縦幅 + + uint map_tile_wid; + uint map_tile_hgt; + + bool map_active; +#if 1 /* #ifdef JP */ + LOGFONT lf; +#endif + + bool posfix; + +}; + +#define MAX_TERM_DATA 8 //!< Maximum number of windows + +static term_data data[MAX_TERM_DATA]; //!< An array of term_data's +static term_data *my_td; //!< Hack -- global "window creation" pointer +POINT normsize; //!< Remember normal size of main window when maxmized + +/* + * was main window maximized on previous playing + */ +bool win_maximized = FALSE; + +/* + * game in progress + */ +bool game_in_progress = FALSE; + +/* + * note when "open"/"new" become valid + */ +bool initialized = FALSE; + +/* + * screen paletted, i.e. 256 colors + */ +bool paletted = FALSE; + +/* + * 16 colors screen, don't use RGB() + */ +bool colors16 = FALSE; + +/* + * Saved instance handle + */ +static HINSTANCE hInstance; + +/* + * Yellow brush for the cursor + */ +static HBRUSH hbrYellow; + +/* + * An icon + */ +static HICON hIcon; + +/* + * A palette + */ +static HPALETTE hPal; + +/* bg */ +static HBITMAP hBG = NULL; +static int use_bg = 0; //!< 背景使用フラグ、1なら私用。 +static char bg_bitmap_file[1024] = "bg.bmp"; //!< 現在の背景ビットマップファイル名。 + +#ifdef USE_SAVER + +/* + * The screen saver window + */ +static HWND hwndSaver; + +#endif /* USE_SAVER */ + + +#ifdef USE_GRAPHICS + +/*! + * 現在使用中のタイルID(0ならば未使用) + * Flag set once "graphics" has been initialized + */ +static byte_hack current_graphics_mode = 0; + +/* + * The global bitmap + */ +static DIBINIT infGraph; + +/* + * The global bitmap mask + */ +static DIBINIT infMask; + +#endif /* USE_GRAPHICS */ + + +#ifdef USE_SOUND + +/* + * Flag set once "sound" has been initialized + */ +static bool can_use_sound = FALSE; + +#define SAMPLE_MAX 8 +/* + * An array of sound file names + */ +static concptr sound_file[SOUND_MAX][SAMPLE_MAX]; + +#endif /* USE_SOUND */ + + + +#ifdef USE_MUSIC + +#define SAMPLE_MUSIC_MAX 16 +static concptr music_file[MUSIC_BASIC_MAX][SAMPLE_MUSIC_MAX]; +static concptr dungeon_music_file[1000][SAMPLE_MUSIC_MAX]; +static concptr town_music_file[1000][SAMPLE_MUSIC_MAX]; +static concptr quest_music_file[1000][SAMPLE_MUSIC_MAX]; +static bool can_use_music = FALSE; + +static MCI_OPEN_PARMS mop; +static char mci_device_type[256]; + +int current_music_type = 0; +int current_music_id = 0; + +#endif /* USE_MUSIC */ + + +/* + * Full path to ANGBAND.INI + */ +static concptr ini_file = NULL; + +/* + * Name of application + */ +static concptr AppName = "ANGBAND"; + +/* + * Name of sub-window type + */ +static concptr AngList = "AngList"; + +/* + * Directory names + */ +static concptr ANGBAND_DIR_XTRA_GRAF; +static concptr ANGBAND_DIR_XTRA_SOUND; +static concptr ANGBAND_DIR_XTRA_MUSIC; +static concptr ANGBAND_DIR_XTRA_HELP; +#if 0 /* #ifndef JP */ +static concptr ANGBAND_DIR_XTRA_FONT; +#endif +#ifdef USE_MUSIC +static concptr ANGBAND_DIR_XTRA_MUSIC; +#endif + + +/* + * The "complex" color values + */ +static COLORREF win_clr[256]; + + +/* + * Flag for macro trigger with dump ASCII + */ +static bool Term_no_press = FALSE; + +/* + * Copy and paste + */ +static bool mouse_down = FALSE; +static bool paint_rect = FALSE; +static TERM_LEN mousex = 0, mousey = 0; +static TERM_LEN oldx, oldy; + + +/*! + * @brief The "simple" color values + * @details + * See "main-ibm.c" for original table information + * The entries below are taken from the "color bits" defined above. + * Note that many of the choices below suck, but so do crappy monitors. + */ +static BYTE win_pal[256] = +{ + VID_BLACK, /* Dark */ + VID_WHITE, /* White */ + VID_CYAN, /* Slate XXX */ + VID_RED | VID_BRIGHT, /* Orange XXX */ + VID_RED, /* Red */ + VID_GREEN, /* Green */ + VID_BLUE, /* Blue */ + VID_YELLOW, /* Umber XXX */ + VID_BLACK | VID_BRIGHT, /* Light Dark */ + VID_CYAN | VID_BRIGHT, /* Light Slate XXX */ + VID_MAGENTA, /* Violet XXX */ + VID_YELLOW | VID_BRIGHT, /* Yellow */ + VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */ + VID_GREEN | VID_BRIGHT, /* Light Green */ + VID_BLUE | VID_BRIGHT, /* Light Blue */ + VID_YELLOW /* Light Umber XXX */ +}; + + +/* + * Hack -- define which keys are "special" + */ +static bool special_key[256]; +static bool ignore_key[256]; + +#if 1 +/* + * Hack -- initialization list for "special_key" + */ +static byte special_key_list[] = { + VK_CLEAR, VK_PAUSE, VK_CAPITAL, + VK_KANA, VK_JUNJA, VK_FINAL, VK_KANJI, + VK_CONVERT, VK_NONCONVERT, VK_ACCEPT, VK_MODECHANGE, + VK_PRIOR, VK_NEXT, VK_END, VK_HOME, + VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, + VK_SELECT, VK_PRINT, VK_EXECUTE, VK_SNAPSHOT, + VK_INSERT, VK_DELETE, VK_HELP, VK_APPS, + VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, + VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, + VK_NUMPAD8, VK_NUMPAD9, VK_MULTIPLY, VK_ADD, + VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE, + VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, + VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, + VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, + VK_F19,VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, + VK_NUMLOCK, VK_SCROLL, VK_ATTN, VK_CRSEL, + VK_EXSEL, VK_EREOF, VK_PLAY, VK_ZOOM, + VK_NONAME, VK_PA1, + 0 /* End of List */ +}; + +static byte ignore_key_list[] = { + VK_ESCAPE, VK_TAB, VK_SPACE, + 'F', 'W', 'O', /*'H',*/ /* these are menu characters.*/ + VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN, + VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, + VK_LMENU, VK_RMENU, + 0 /* End of List */ +}; +#else +/* + * Hack -- initialization list for "special_key" + * + * We ignore the modifier keys (shift, control, alt, num lock, scroll lock), + * and the normal keys (escape, tab, return, letters, numbers, etc), but we + * catch the keypad keys (with and without numlock set, including keypad 5), + * the function keys (including the "menu" key which maps to F10), and the + * "pause" key (between scroll lock and numlock). We also catch a few odd + * keys which I do not recognize, but which are listed among keys which we + * do catch, so they should be harmless to catch. + */ +static byte special_key_list[] = +{ + VK_CLEAR, /* 0x0C (KP<5>) */ + + VK_PAUSE, /* 0x13 (pause) */ + + VK_PRIOR, /* 0x21 (KP<9>) */ + VK_NEXT, /* 0x22 (KP<3>) */ + VK_END, /* 0x23 (KP<1>) */ + VK_HOME, /* 0x24 (KP<7>) */ + VK_LEFT, /* 0x25 (KP<4>) */ + VK_UP, /* 0x26 (KP<8>) */ + VK_RIGHT, /* 0x27 (KP<6>) */ + VK_DOWN, /* 0x28 (KP<2>) */ + VK_SELECT, /* 0x29 (?????) */ + VK_PRINT, /* 0x2A (?????) */ + VK_EXECUTE, /* 0x2B (?????) */ + VK_SNAPSHOT, /* 0x2C (?????) */ + VK_INSERT, /* 0x2D (KP<0>) */ + VK_DELETE, /* 0x2E (KP<.>) */ + VK_HELP, /* 0x2F (?????) */ +#if 0 + VK_NUMPAD0, /* 0x60 (KP<0>) */ + VK_NUMPAD1, /* 0x61 (KP<1>) */ + VK_NUMPAD2, /* 0x62 (KP<2>) */ + VK_NUMPAD3, /* 0x63 (KP<3>) */ + VK_NUMPAD4, /* 0x64 (KP<4>) */ + VK_NUMPAD5, /* 0x65 (KP<5>) */ + VK_NUMPAD6, /* 0x66 (KP<6>) */ + VK_NUMPAD7, /* 0x67 (KP<7>) */ + VK_NUMPAD8, /* 0x68 (KP<8>) */ + VK_NUMPAD9, /* 0x69 (KP<9>) */ + VK_MULTIPLY, /* 0x6A (KP<*>) */ + VK_ADD, /* 0x6B (KP<+>) */ + VK_SEPARATOR, /* 0x6C (?????) */ + VK_SUBTRACT, /* 0x6D (KP<->) */ + VK_DECIMAL, /* 0x6E (KP<.>) */ + VK_DIVIDE, /* 0x6F (KP) */ +#endif + VK_F1, /* 0x70 */ + VK_F2, /* 0x71 */ + VK_F3, /* 0x72 */ + VK_F4, /* 0x73 */ + VK_F5, /* 0x74 */ + VK_F6, /* 0x75 */ + VK_F7, /* 0x76 */ + VK_F8, /* 0x77 */ + VK_F9, /* 0x78 */ + VK_F10, /* 0x79 */ + VK_F11, /* 0x7A */ + VK_F12, /* 0x7B */ + VK_F13, /* 0x7C */ + VK_F14, /* 0x7D */ + VK_F15, /* 0x7E */ + VK_F16, /* 0x7F */ + VK_F17, /* 0x80 */ + VK_F18, /* 0x81 */ + VK_F19, /* 0x82 */ + VK_F20, /* 0x83 */ + VK_F21, /* 0x84 */ + VK_F22, /* 0x85 */ + VK_F23, /* 0x86 */ + VK_F24, /* 0x87 */ + 0 +}; +#endif + + +/* Function prototype */ + +static bool is_already_running(void); + + +/* bg */ +static void delete_bg(void) +{ + if (hBG != NULL) + { + DeleteObject(hBG); + hBG = NULL; + } +} + +static int init_bg(void) +{ + char * bmfile = bg_bitmap_file; + + delete_bg(); + if (use_bg == 0) return 0; + + hBG = LoadImage(NULL, bmfile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if (!hBG) { + plog_fmt(_("壁紙用ビットマップ '%s' を読み込めません。", "Can't load the bitmap file '%s'."), bmfile); + use_bg = 0; + return 0; + } + use_bg = 1; + return 1; +} + +static void DrawBG(HDC hdc, RECT *r) +{ + HDC hdcSrc; + HBITMAP hOld; + BITMAP bm; + int x = r->left, y = r->top; + int nx, ny, sx, sy, swid, shgt, cwid, chgt; + + if (!use_bg || !hBG) + return; + + nx = x; ny = y; + GetObject(hBG, sizeof(bm), &bm); + swid = bm.bmWidth; shgt = bm.bmHeight; + + hdcSrc = CreateCompatibleDC(hdc); + hOld = SelectObject(hdcSrc, hBG); + + do { + sx = nx % swid; + cwid = MIN(swid - sx, r->right - nx); + do { + sy = ny % shgt; + chgt = MIN(shgt - sy, r->bottom - ny); + BitBlt(hdc, nx, ny, cwid, chgt, hdcSrc, sx, sy, SRCCOPY); + ny += chgt; + } while (ny < r->bottom); + ny = y; + nx += cwid; + } while (nx < r->right); + + SelectObject(hdcSrc, hOld); + DeleteDC(hdcSrc); +} + +#if 0 +/* + * Hack -- given a pathname, point at the filename + */ +static concptr extract_file_name(concptr s) +{ + concptr p; + + /* Start at the end */ + p = s + strlen(s) - 1; + + /* Back up to divider */ + while ((p >= s) && (*p != ':') && (*p != '\\')) p--; + + /* Return file name */ + return (p+1); +} +#endif + + +/* + * Hack -- given a simple filename, extract the "font size" info + * + * Return a pointer to a static buffer holding the capitalized base name. + */ +#if 0 /* #ifndef JP */ +static char *analyze_font(char *path, int *wp, int *hp) +{ + int wid, hgt; + + char *s, *p; + + /* Start at the end */ + p = path + strlen(path) - 1; + + /* Back up to divider */ + while ((p >= path) && (*p != ':') && (*p != '\\')) --p; + + /* Advance to file name */ + ++p; + + /* Capitalize */ + for (s = p; *s; ++s) + { + /* Capitalize (be paranoid) */ + if (islower(*s)) *s = toupper(*s); + } + + /* Find first 'X' */ + s = my_strchr(p, 'X'); + + /* Extract font width */ + wid = atoi(p); + + /* Extract height */ + hgt = s ? atoi(s+1) : 0; + + /* Save results */ + (*wp) = wid; + (*hp) = hgt; + return (p); +} +#endif + + +/* + * Check for existance of a file + */ +static bool check_file(concptr s) +{ + char path[1024]; + +#ifdef WIN32 + + DWORD attrib; + +#else /* WIN32 */ + + unsigned int attrib; + +#endif /* WIN32 */ + + /* Copy it */ + strcpy(path, s); + +#ifdef WIN32 + + /* Examine */ + attrib = GetFileAttributes(path); + + /* Require valid filename */ + if (attrib == INVALID_FILE_NAME) return (FALSE); + + /* Prohibit directory */ + if (attrib & FILE_ATTRIBUTE_DIRECTORY) return (FALSE); + +#else /* WIN32 */ + + /* Examine and verify */ + if (_dos_getfileattr(path, &attrib)) return (FALSE); + + /* Prohibit something */ + if (attrib & FA_LABEL) return (FALSE); + + /* Prohibit directory */ + if (attrib & FA_DIREC) return (FALSE); + +#endif /* WIN32 */ + + /* Success */ + return (TRUE); +} + + +/* + * Check for existance of a directory + */ +static bool check_dir(concptr s) +{ + int i; + + char path[1024]; + +#ifdef WIN32 + + DWORD attrib; + +#else /* WIN32 */ + + unsigned int attrib; + +#endif /* WIN32 */ + + /* Copy it */ + strcpy(path, s); + + /* Check length */ + i = strlen(path); + + /* Remove trailing backslash */ + if (i && (path[i-1] == '\\')) path[--i] = '\0'; + +#ifdef WIN32 + + /* Examine */ + attrib = GetFileAttributes(path); + + /* Require valid filename */ + if (attrib == INVALID_FILE_NAME) return (FALSE); + + /* Require directory */ + if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) return (FALSE); + +#else /* WIN32 */ + + /* Examine and verify */ + if (_dos_getfileattr(path, &attrib)) return (FALSE); + + /* Prohibit something */ + if (attrib & FA_LABEL) return (FALSE); + + /* Require directory */ + if (!(attrib & FA_DIREC)) return (FALSE); + +#endif /* WIN32 */ + + /* Success */ + return (TRUE); +} + + +/* + * Validate a file + */ +static void validate_file(concptr s) +{ + /* Verify or fail */ + if (!check_file(s)) + { + quit_fmt(_("必要なファイル[%s]が見あたりません。", "Cannot find required file:\n%s"), s); + } +} + + +/* + * Validate a directory + */ +static void validate_dir(concptr s, bool vital) +{ + /* Verify or fail */ + if (!check_dir(s)) + { + /* This directory contains needed data */ + if (vital) + { + quit_fmt(_("必要なディレクトリ[%s]が見あたりません。", "Cannot find required directory:\n%s"), s); + } + /* Attempt to create this directory */ + else if (mkdir(s)) + { + quit_fmt("Unable to create directory:\n%s", s); + } + } +} + + +/*! + * @brief (Windows版固有実装)Get the "size" for a window + */ +static void term_getsize(term_data *td) +{ + RECT rc; + TERM_LEN wid, hgt; + + /* Paranoia */ + if (td->cols < 1) td->cols = 1; + if (td->rows < 1) td->rows = 1; + + /* Window sizes */ + wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2; + hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2; + + /* Fake window size */ + rc.left = 0; + rc.right = rc.left + wid; + rc.top = 0; + rc.bottom = rc.top + hgt; + + /* rc.right += 1; */ + /* rc.bottom += 1; */ + + /* Adjust */ + AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); + + /* Total size */ + td->size_wid = rc.right - rc.left; + td->size_hgt = rc.bottom - rc.top; + + /* See CreateWindowEx */ + if (!td->w) return; + + /* Extract actual location */ + GetWindowRect(td->w, &rc); + + /* Save the location */ + td->pos_x = rc.left; + td->pos_y = rc.top; +} + + +/* + * Write the "prefs" for a single term + */ +static void save_prefs_aux(int i) +{ + term_data *td = &data[i]; + GAME_TEXT sec_name[128]; + char buf[1024]; + + RECT rc; + WINDOWPLACEMENT lpwndpl; + + /* Paranoia */ + if (!td->w) return; + + /* Make section name */ + sprintf(sec_name, "Term-%d", i); + + /* Visible */ + if (i > 0) + { + strcpy(buf, td->visible ? "1" : "0"); + WritePrivateProfileString(sec_name, "Visible", buf, ini_file); + } + + /* Font */ +#ifdef JP + strcpy(buf, td->lf.lfFaceName[0]!='\0' ? td->lf.lfFaceName : "MS ゴシック"); +#else +#if 0 + strcpy(buf, td->font_file ? td->font_file : "8X13.FON"); +#else + strcpy(buf, td->lf.lfFaceName[0]!='\0' ? td->lf.lfFaceName : "Courier"); +#endif +#endif + + WritePrivateProfileString(sec_name, "Font", buf, ini_file); + +#if 1 /* #ifdef JP */ + wsprintf(buf, "%d", td->lf.lfWidth); + WritePrivateProfileString(sec_name, "FontWid", buf, ini_file); + wsprintf(buf, "%d", td->lf.lfHeight); + WritePrivateProfileString(sec_name, "FontHgt", buf, ini_file); + wsprintf(buf, "%d", td->lf.lfWeight); + WritePrivateProfileString(sec_name, "FontWgt", buf, ini_file); +#endif + /* Bizarre */ + strcpy(buf, td->bizarre ? "1" : "0"); + WritePrivateProfileString(sec_name, "Bizarre", buf, ini_file); + + /* Tile size (x) */ + wsprintf(buf, "%d", td->tile_wid); + WritePrivateProfileString(sec_name, "TileWid", buf, ini_file); + + /* Tile size (y) */ + wsprintf(buf, "%d", td->tile_hgt); + WritePrivateProfileString(sec_name, "TileHgt", buf, ini_file); + + /* Get window placement and dimensions */ + lpwndpl.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(td->w, &lpwndpl); + + /* Acquire position in *normal* mode (not minimized) */ + rc = lpwndpl.rcNormalPosition; + + /* Window size (x) */ + if (i == 0) wsprintf(buf, "%d", normsize.x); + else wsprintf(buf, "%d", td->cols); + WritePrivateProfileString(sec_name, "NumCols", buf, ini_file); + + /* Window size (y) */ + if (i == 0) wsprintf(buf, "%d", normsize.y); + else wsprintf(buf, "%d", td->rows); + WritePrivateProfileString(sec_name, "NumRows", buf, ini_file); + + /* Maxmized (only main window) */ + if (i == 0) + { + strcpy(buf, IsZoomed(td->w) ? "1" : "0"); + WritePrivateProfileString(sec_name, "Maximized", buf, ini_file); + } + + /* Acquire position */ + GetWindowRect(td->w, &rc); + + /* Window position (x) */ + wsprintf(buf, "%d", rc.left); + WritePrivateProfileString(sec_name, "PositionX", buf, ini_file); + + /* Window position (y) */ + wsprintf(buf, "%d", rc.top); + WritePrivateProfileString(sec_name, "PositionY", buf, ini_file); + + /* Window Z position */ + if (i > 0) + { + strcpy(buf, td->posfix ? "1" : "0"); + WritePrivateProfileString(sec_name, "PositionFix", buf, ini_file); + } +} + + +/* + * Write the "prefs" + * We assume that the windows have all been initialized + */ +static void save_prefs(void) +{ + int i; + + char buf[128]; + + /* Save the "arg_graphics" flag */ + sprintf(buf, "%d", arg_graphics); + WritePrivateProfileString("Angband", "Graphics", buf, ini_file); + + /* Save the "arg_bigtile" flag */ + strcpy(buf, arg_bigtile ? "1" : "0"); + WritePrivateProfileString("Angband", "Bigtile", buf, ini_file); + + /* Save the "arg_sound" flag */ + strcpy(buf, arg_sound ? "1" : "0"); + WritePrivateProfileString("Angband", "Sound", buf, ini_file); + + /* Save the "arg_sound" flag */ + strcpy(buf, arg_music ? "1" : "0"); + WritePrivateProfileString("Angband", "Music", buf, ini_file); + + /* bg */ + strcpy(buf, use_bg ? "1" : "0"); + WritePrivateProfileString("Angband", "BackGround", buf, ini_file); + WritePrivateProfileString("Angband", "BackGroundBitmap", + bg_bitmap_file[0] != '\0' ? bg_bitmap_file : "bg.bmp", ini_file); + + /* Save window prefs */ + for (i = 0; i < MAX_TERM_DATA; ++i) + { + save_prefs_aux(i); + } +} + + +/* + * Load the "prefs" for a single term + */ +static void load_prefs_aux(int i) +{ + term_data *td = &data[i]; + GAME_TEXT sec_name[128]; + char tmp[1024]; + + int wid, hgt, posx, posy; + int dispx = GetSystemMetrics( SM_CXVIRTUALSCREEN); + int dispy = GetSystemMetrics( SM_CYVIRTUALSCREEN); + posx=0; + posy=0; + + /* Make section name */ + sprintf(sec_name, "Term-%d", i); + + /* Make section name */ + sprintf(sec_name, "Term-%d", i); + + /* Visible */ + if (i > 0) + { + td->visible = (GetPrivateProfileInt(sec_name, "Visible", td->visible, ini_file) != 0); + } + + /* Desired font, with default */ +#ifdef JP + GetPrivateProfileString(sec_name, "Font", "MS ゴシック", tmp, 127, ini_file); +#else +#if 0 + GetPrivateProfileString(sec_name, "Font", "8X13.FON", tmp, 127, ini_file); +#else + GetPrivateProfileString(sec_name, "Font", "Courier", tmp, 127, ini_file); +#endif +#endif + + + /* Bizarre */ + td->bizarre = (GetPrivateProfileInt(sec_name, "Bizarre", td->bizarre, ini_file) != 0); + + /* Analyze font, save desired font name */ +#if 1 /* #ifdef JP */ + td->font_want = string_make(tmp); + hgt = 15; wid = 0; + td->lf.lfWidth = GetPrivateProfileInt(sec_name, "FontWid", wid, ini_file); + td->lf.lfHeight = GetPrivateProfileInt(sec_name, "FontHgt", hgt, ini_file); + td->lf.lfWeight = GetPrivateProfileInt(sec_name, "FontWgt", 0, ini_file); +#else + td->font_want = string_make(analyze_font(tmp, &wid, &hgt)); +#endif + + + /* Tile size */ +#if 1 /* #ifdef JP */ + td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", td->lf.lfWidth, ini_file); + td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", td->lf.lfHeight, ini_file); +#else + td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", wid, ini_file); + td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", hgt, ini_file); +#endif + + + /* Window size */ + td->cols = GetPrivateProfileInt(sec_name, "NumCols", td->cols, ini_file); + td->rows = GetPrivateProfileInt(sec_name, "NumRows", td->rows, ini_file); + normsize.x = td->cols; normsize.y = td->rows; + + /* Window size */ + if (i == 0) + { + win_maximized = (GetPrivateProfileInt(sec_name, "Maximized", win_maximized, ini_file) != 0); + } + + /* Window position */ + posx = GetPrivateProfileInt(sec_name, "PositionX", posx, ini_file); + posy = GetPrivateProfileInt(sec_name, "PositionY", posy, ini_file); + td->pos_x = MIN(MAX(0, posx), dispx-128); + td->pos_y = MIN(MAX(0, posy), dispy-128); + + /* Window Z position */ + if (i > 0) + { + td->posfix = (GetPrivateProfileInt(sec_name, "PositionFix", td->posfix, ini_file) != 0); + } +} + + +/* + * Load the "prefs" + */ +static void load_prefs(void) +{ + int i; + + /* Extract the "arg_graphics" flag */ + arg_graphics = (byte_hack)GetPrivateProfileInt("Angband", "Graphics", GRAPHICS_NONE, ini_file); + + /* Extract the "arg_bigtile" flag */ + arg_bigtile = (GetPrivateProfileInt("Angband", "Bigtile", FALSE, ini_file) != 0); + use_bigtile = arg_bigtile; + + /* Extract the "arg_sound" flag */ + arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0); + + /* Extract the "arg_sound" flag */ + arg_music = (GetPrivateProfileInt("Angband", "Music", 0, ini_file) != 0); + + /* bg */ + use_bg = GetPrivateProfileInt("Angband", "BackGround", 0, ini_file); + GetPrivateProfileString("Angband", "BackGroundBitmap", "bg.bmp", bg_bitmap_file, 1023, ini_file); + + /* Load window prefs */ + for (i = 0; i < MAX_TERM_DATA; ++i) + { + load_prefs_aux(i); + } +} + +#if defined(USE_SOUND) || defined(USE_MUSIC) + +/* + * - Taken from files.c. + * + * Extract "tokens" from a buffer + * + * This function uses "whitespace" as delimiters, and treats any amount of + * whitespace as a single delimiter. We will never return any empty tokens. + * When given an empty buffer, or a buffer containing only "whitespace", we + * will return no tokens. We will never extract more than "num" tokens. + * + * By running a token through the "text_to_ascii()" function, you can allow + * that token to include (encoded) whitespace, using "\s" to encode spaces. + * + * We save pointers to the tokens in "tokens", and return the number found. + */ +static s16b tokenize_whitespace(char *buf, s16b num, char **tokens) +{ + s16b k = 0; + char *s = buf; + + /* Process */ + while (k < num) + { + char *t; + + /* Skip leading whitespace */ + for ( ; *s && iswspace(*s); ++s) /* loop */; + + /* All done */ + if (!*s) break; + + /* Find next whitespace, if any */ + for (t = s; *t && !iswspace(*t); ++t) /* loop */; + + /* Nuke and advance (if necessary) */ + if (*t) *t++ = '\0'; + + /* Save the token */ + tokens[k++] = s; + + /* Advance */ + s = t; + } + + /* Count */ + return (k); +} + +#endif /* USE_SOUND || USE_MUSIC */ + +#ifdef USE_SOUND + +static void load_sound_prefs(void) +{ + int i, j, num; + char tmp[1024]; + char ini_path[1024]; + char wav_path[1024]; + char *zz[SAMPLE_MAX]; + + /* Access the sound.cfg */ + + path_build(ini_path, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.cfg"); + + for (i = 0; i < SOUND_MAX; i++) + { + GetPrivateProfileString("Sound", angband_sound_name[i], "", tmp, 1024, ini_path); + + num = tokenize_whitespace(tmp, SAMPLE_MAX, zz); + + for (j = 0; j < num; j++) + { + /* Access the sound */ + path_build(wav_path, 1024, ANGBAND_DIR_XTRA_SOUND, zz[j]); + + /* Save the sound filename, if it exists */ + if (check_file(wav_path)) + sound_file[i][j] = string_make(zz[j]); + } + } +} + +#endif /* USE_SOUND */ + +#ifdef USE_MUSIC + +static void load_music_prefs(void) +{ + int i, j, num; + char tmp[1024]; + char ini_path[1024]; + char wav_path[1024]; + char *zz[SAMPLE_MAX]; + char key[80]; + + /* Access the music.cfg */ + + path_build(ini_path, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.cfg"); + + GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path); + + for (i = 0; i < MUSIC_BASIC_MAX; i++) + { + GetPrivateProfileString("Basic", angband_music_basic_name[i], "", tmp, 1024, ini_path); + + num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); + + for (j = 0; j < num; j++) + { + /* Access the sound */ + path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); + + /* Save the sound filename, if it exists */ + if (check_file(wav_path)) + music_file[i][j] = string_make(zz[j]); + } + } + + for (i = 0; i < max_d_idx; i++) + { + sprintf(key, "dungeon%03d", i); + GetPrivateProfileString("Dungeon", key, "", tmp, 1024, ini_path); + + num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); + + for (j = 0; j < num; j++) + { + /* Access the sound */ + path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); + + /* Save the sound filename, if it exists */ + if (check_file(wav_path)) + dungeon_music_file[i][j] = string_make(zz[j]); + } + } + + for (i = 0; i < max_q_idx; i++) + { + sprintf(key, "quest%03d", i); + GetPrivateProfileString("Quest", key, "", tmp, 1024, ini_path); + + num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); + + for (j = 0; j < num; j++) + { + /* Access the sound */ + path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); + + /* Save the sound filename, if it exists */ + if (check_file(wav_path)) + quest_music_file[i][j] = string_make(zz[j]); + } + } + + for (i = 0; i < 1000; i++) /*!< @todo 町最大数指定 */ + { + sprintf(key, "town%03d", i); + GetPrivateProfileString("Town", key, "", tmp, 1024, ini_path); + + num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz); + + for (j = 0; j < num; j++) + { + /* Access the sound */ + path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]); + + /* Save the sound filename, if it exists */ + if (check_file(wav_path)) + town_music_file[i][j] = string_make(zz[j]); + } + } + + +} + +#endif /* USE_MUSIC */ + +/* + * Create the new global palette based on the bitmap palette + * (if any), and the standard 16 entry palette derived from + * "win_clr[]" which is used for the basic 16 Angband colors. + * + * This function is never called before all windows are ready. + * + * This function returns FALSE if the new palette could not be + * prepared, which should normally be a fatal error. XXX XXX + * + * Note that only some machines actually use a "palette". + */ +static int new_palette(void) +{ + HPALETTE hBmPal; + HPALETTE hNewPal; + HDC hdc; + int i, nEntries; + int pLogPalSize; + int lppeSize; + LPLOGPALETTE pLogPal; + LPPALETTEENTRY lppe; + + term_data *td; + + + /* This makes no sense */ + if (!paletted) return (TRUE); + + + /* No bitmap */ + lppeSize = 0; + lppe = NULL; + nEntries = 0; + +#ifdef USE_GRAPHICS + + /* Check the bitmap palette */ + hBmPal = infGraph.hPalette; + + /* Use the bitmap */ + if (hBmPal) + { + lppeSize = 256 * sizeof(PALETTEENTRY); + lppe = (LPPALETTEENTRY)ralloc(lppeSize); + nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe); + if ((nEntries == 0) || (nEntries > 220)) + { + /* Warn the user */ + plog(_("画面を16ビットか24ビットカラーモードにして下さい。", "Please switch to high- or true-color mode.")); + + /* Cleanup */ + rnfree(lppe, lppeSize); + + /* Fail */ + return (FALSE); + } + } + +#endif /* USE_GRAPHICS */ + + /* Size of palette */ + pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY); + + /* Allocate palette */ + pLogPal = (LPLOGPALETTE)ralloc(pLogPalSize); + + /* Version */ + pLogPal->palVersion = 0x300; + + /* Make room for bitmap and normal data */ + pLogPal->palNumEntries = nEntries + 16; + + /* Save the bitmap data */ + for (i = 0; i < nEntries; i++) + { + pLogPal->palPalEntry[i] = lppe[i]; + } + + /* Save the normal data */ + for (i = 0; i < 16; i++) + { + LPPALETTEENTRY p; + + /* Access the entry */ + p = &(pLogPal->palPalEntry[i+nEntries]); + + /* Save the colors */ + p->peRed = GetRValue(win_clr[i]); + p->peGreen = GetGValue(win_clr[i]); + p->peBlue = GetBValue(win_clr[i]); + + /* Save the flags */ + p->peFlags = PC_NOCOLLAPSE; + } + + /* Free something */ + if (lppe) rnfree(lppe, lppeSize); + + /* Create a new palette, or fail */ + hNewPal = CreatePalette(pLogPal); + if (!hNewPal) quit(_("パレットを作成できません!", "Cannot create palette!")); + + /* Free the palette */ + rnfree(pLogPal, pLogPalSize); + + /* Main window */ + td = &data[0]; + + /* Realize the palette */ + hdc = GetDC(td->w); + SelectPalette(hdc, hNewPal, 0); + i = RealizePalette(hdc); + ReleaseDC(td->w, hdc); + if (i == 0) quit(_("パレットをシステムエントリにマップできません!", "Cannot realize palette!")); + + + /* Sub-windows */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + td = &data[i]; + + hdc = GetDC(td->w); + SelectPalette(hdc, hNewPal, 0); + ReleaseDC(td->w, hdc); + } + + /* Delete old palette */ + if (hPal) DeleteObject(hPal); + + /* Save new palette */ + hPal = hNewPal; + + /* Success */ + return (TRUE); +} + + +#ifdef USE_GRAPHICS +/*! + * @brief グラフィクスを初期化する / Initialize graphics + * @details + *
    + *
  • メニュー[オプション]>[グラフィクス]が「なし」以外の時に描画処理を初期化する。
  • + *
  • 呼び出されるタイミングはロード時、及び同メニューで「なし」以外に変更される毎になる。
  • + *
+ */ +static bool init_graphics(void) +{ + /* Initialize once */ + char buf[1024]; + BYTE wid, hgt, twid, thgt, ox, oy; + concptr name; + + if (arg_graphics == GRAPHICS_ADAM_BOLT) + { + wid = 16; + hgt = 16; + twid = 16; + thgt = 16; + ox = 0; + oy = 0; + name = "16X16.BMP"; + + ANGBAND_GRAF = "new"; + } + else if (arg_graphics == GRAPHICS_HENGBAND) + { + /*! @todo redraw + wid = 64; + hgt = 64; + twid = 32; + thgt = 32; + ox = -16; + oy = -24; + name = "64X64.BMP"; + */ + + wid = 32; + hgt = 32; + twid = 32; + thgt = 32; + ox = 0; + oy = 0; + name = "32X32.BMP"; + + ANGBAND_GRAF = "ne2"; + } + else + { + wid = 8; + hgt = 8; + twid = 8; + thgt = 8; + ox = 0; + oy = 0; + name = "8X8.BMP"; + ANGBAND_GRAF = "old"; + } + + /* Access the bitmap file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name); + + /* Load the bitmap or quit */ + if (!ReadDIB(data[0].w, buf, &infGraph)) + { + plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name); + return (FALSE); + } + + /* Save the new sizes */ + infGraph.CellWidth = wid; + infGraph.CellHeight = hgt; + infGraph.TileWidth = twid; + infGraph.TileHeight = thgt; + infGraph.OffsetX = ox; + infGraph.OffsetY = oy; + + if (arg_graphics == GRAPHICS_ADAM_BOLT) + { + /* Access the mask file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask.bmp"); + + /* Load the bitmap or quit */ + if (!ReadDIB(data[0].w, buf, &infMask)) + { + plog_fmt("Cannot read bitmap file '%s'", buf); + return (FALSE); + } + } + if (arg_graphics == GRAPHICS_HENGBAND) + { + /* Access the mask file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, "mask32.bmp"); + + /* Load the bitmap or quit */ + if (!ReadDIB(data[0].w, buf, &infMask)) + { + plog_fmt("Cannot read bitmap file '%s'", buf); + return (FALSE); + } + } + + /* Activate a palette */ + if (!new_palette()) + { + /* Free bitmap */ + + plog(_("パレットを実現できません!", "Cannot activate palette!")); + return (FALSE); + } + + /* Graphics available */ + current_graphics_mode = arg_graphics; + return (current_graphics_mode); +} +#endif /* USE_GRAPHICS */ + + +#ifdef USE_MUSIC +/* + * Initialize music + */ +static bool init_music(void) +{ + /* Initialize once */ + if (!can_use_music) + { + /* Load the prefs */ + load_music_prefs(); + + /* Sound available */ + can_use_music = TRUE; + } + return (can_use_music); +} + +/* + * Hack -- Stop a music + */ +static void stop_music(void) +{ + mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); + mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); +} + +#endif /* USE_MUSIC */ + +#ifdef USE_SOUND +/* + * Initialize sound + */ +static bool init_sound(void) +{ + /* Initialize once */ + if (!can_use_sound) + { + /* Load the prefs */ + load_sound_prefs(); + + /* Sound available */ + can_use_sound = TRUE; + } + return (can_use_sound); +} +#endif /* USE_SOUND */ + + +/* + * Resize a window + */ +static void term_window_resize(term_data *td) +{ + /* Require window */ + if (!td->w) return; + + /* Resize the window */ + SetWindowPos(td->w, 0, 0, 0, + td->size_wid, td->size_hgt, + SWP_NOMOVE | SWP_NOZORDER); + + /* Redraw later */ + InvalidateRect(td->w, NULL, TRUE); +} + + +/* + * Force the use of a new "font file" for a term_data + * + * This function may be called before the "window" is ready + * + * This function returns zero only if everything succeeds. + * + * Note that the "font name" must be capitalized!!! + */ +static errr term_force_font(term_data *td, concptr path) +{ + int wid, hgt; + +#if 0 /* #ifndef JP */ + int i; + char *base; + char buf[1024]; +#endif + + /* Forget the old font (if needed) */ + if (td->font_id) DeleteObject(td->font_id); + +#if 1 /* #ifdef JP */ + /* Unused */ + (void)path; + + /* Create the font (using the 'base' of the font file name!) */ + td->font_id = CreateFontIndirect(&(td->lf)); + wid = td->lf.lfWidth; + hgt = td->lf.lfHeight; + if (!td->font_id) return (1); +#else + /* Forget old font */ + if (td->font_file) + { + bool used = FALSE; + + /* Scan windows */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + /* Don't check when closing the application */ + if (!path) break; + + /* Check "screen" */ + if ((td != &data[i]) && + (data[i].font_file) && + (streq(data[i].font_file, td->font_file))) + { + used = TRUE; + } + } + + /* Remove unused font resources */ + if (!used) RemoveFontResource(td->font_file); + + /* Free the old name */ + string_free(td->font_file); + + /* Forget it */ + td->font_file = NULL; + } + + /* No path given */ + if (!path) return (1); + + /* Local copy */ + strcpy(buf, path); + + /* Analyze font path */ + base = analyze_font(buf, &wid, &hgt); + + /* Verify suffix */ + if (!suffix(base, ".FON")) return (1); + + /* Verify file */ + if (!check_file(buf)) return (1); + + /* Load the new font */ + if (!AddFontResource(buf)) return (1); + + /* Save new font name */ + td->font_file = string_make(base); + + /* Remove the "suffix" */ + base[strlen(base)-4] = '\0'; + + /* Create the font (using the 'base' of the font file name!) */ + td->font_id = CreateFont(hgt, wid, 0, 0, FW_DONTCARE, 0, 0, 0, + ANSI_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FIXED_PITCH | FF_DONTCARE, base); +#endif + + /* Hack -- Unknown size */ + if (!wid || !hgt) + { + HDC hdcDesktop; + HFONT hfOld; + TEXTMETRIC tm; + + /* all this trouble to get the cell size */ + hdcDesktop = GetDC(HWND_DESKTOP); + hfOld = SelectObject(hdcDesktop, td->font_id); + GetTextMetrics(hdcDesktop, &tm); + SelectObject(hdcDesktop, hfOld); + ReleaseDC(HWND_DESKTOP, hdcDesktop); + + /* Font size info */ + wid = tm.tmAveCharWidth; + hgt = tm.tmHeight; + } + + /* Save the size info */ + td->font_wid = wid; + td->font_hgt = hgt; + + /* Success */ + return (0); +} + + + +/* + * Allow the user to change the font for this window. + */ +static void term_change_font(term_data *td) +{ +#if 1 /* #ifdef JP */ + CHOOSEFONT cf; + + memset(&cf, 0, sizeof(cf)); + cf.lStructSize = sizeof(cf); + cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_NOVERTFONTS | CF_INITTOLOGFONTSTRUCT; + cf.lpLogFont = &(td->lf); + + if (ChooseFont(&cf)) + { + /* Force the font */ + term_force_font(td, NULL); + + /* Assume not bizarre */ + td->bizarre = TRUE; + + /* Reset the tile info */ + td->tile_wid = td->font_wid; + td->tile_hgt = td->font_hgt; + + /* Analyze the font */ + term_getsize(td); + + /* Resize the window */ + term_window_resize(td); + } + +#else + OPENFILENAME ofn; + + char tmp[1024] = ""; + + /* Extract a default if possible */ + if (td->font_file) strcpy(tmp, td->font_file); + + /* Ask for a choice */ + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = data[0].w; + ofn.lpstrFilter = "Angband Font Files (*.fon)\0*.fon\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = tmp; + ofn.nMaxFile = 128; + ofn.lpstrInitialDir = ANGBAND_DIR_XTRA_FONT; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + ofn.lpstrDefExt = "fon"; + + /* Force choice if legal */ + if (GetOpenFileName(&ofn)) + { + /* Force the font */ + if (term_force_font(td, tmp)) + { + /* Access the standard font file */ + path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); + + /* Force the use of that font */ + (void)term_force_font(td, tmp); + } + + /* Assume not bizarre */ + td->bizarre = FALSE; + + /* Reset the tile info */ + td->tile_wid = td->font_wid; + td->tile_hgt = td->font_hgt; + + /* Analyze the font */ + term_getsize(td); + + /* Resize the window */ + term_window_resize(td); + } +#endif + +} + +/* + * Allow the user to lock this window. + */ +static void term_window_pos(term_data *td, HWND hWnd) +{ + SetWindowPos(td->w, hWnd, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +static void windows_map(void); + +/* + * Hack -- redraw a term_data + */ +static void term_data_redraw(term_data *td) +{ + if (td->map_active) + { + /* Redraw the map */ + windows_map(); + } + else + { + /* Activate the term */ + Term_activate(&td->t); + + /* Redraw the contents */ + Term_redraw(); + + /* Restore the term */ + Term_activate(term_screen); + } +} + + +void Term_inversed_area(HWND hWnd, int x, int y, int w, int h) +{ + HDC hdc; + HPEN oldPen; + HBRUSH myBrush, oldBrush; + + term_data *td = (term_data *)GetWindowLong(hWnd, 0); + int tx = td->size_ow1 + x * td->tile_wid; + int ty = td->size_oh1 + y * td->tile_hgt; + int tw = w * td->tile_wid - 1; + int th = h * td->tile_hgt - 1; + + hdc = GetDC(hWnd); + myBrush = CreateSolidBrush(RGB(255, 255, 255)); + oldBrush = SelectObject(hdc, myBrush); + oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); + + PatBlt(hdc, tx, ty, tw, th, PATINVERT); + + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); +} + + + +/*** Function hooks needed by "Term" ***/ + + +#if 0 + +/* + * Initialize a new Term + */ +static void Term_init_win(term *t) +{ + /* XXX Unused */ +} + + +/* + * Nuke an old Term + */ +static void Term_nuke_win(term *t) +{ + /* XXX Unused */ +} + +#endif + + +/*! + * @brief //!< Windows版ユーザ設定項目実装部(実装必須) /Interact with the User + */ +static errr Term_user_win(int n) +{ + /* Unused */ + (void)n; + + /* Success */ + return (0); +} + + +/* + * React to global changes + */ +static errr Term_xtra_win_react(void) +{ + int i; + + /* Simple color */ + if (colors16) + { + /* Save the default colors */ + for (i = 0; i < 256; i++) + { + /* Simply accept the desired colors */ + win_pal[i] = angband_color_table[i][0]; + } + } + + /* Complex color */ + else + { + COLORREF code; + + byte rv, gv, bv; + + bool change = FALSE; + + /* Save the default colors */ + for (i = 0; i < 256; i++) + { + /* Extract desired values */ + rv = angband_color_table[i][1]; + gv = angband_color_table[i][2]; + bv = angband_color_table[i][3]; + + /* Extract a full color code */ + code = PALETTERGB(rv, gv, bv); + + /* Activate changes */ + if (win_clr[i] != code) + { + /* Note the change */ + change = TRUE; + + /* Apply the desired color */ + win_clr[i] = code; + } + } + + /* Activate the palette if needed */ + if (change) (void)new_palette(); + } + + +#ifdef USE_SOUND + + /* Handle "arg_sound" */ + if (use_sound != arg_sound) + { + /* Initialize (if needed) */ + if (arg_sound && !init_sound()) + { + /* Warning */ + plog(_("サウンドを初期化できません!", "Cannot initialize sound!")); + + /* Cannot enable */ + arg_sound = FALSE; + } + + /* Change setting */ + use_sound = arg_sound; + } + +#endif + +#ifdef USE_MUSIC + + /* Handle "arg_sound" */ + if (use_music != arg_music) + { + /* Initialize (if needed) */ + if (arg_music && !init_music()) + { + /* Warning */ + plog(_("BGMを初期化できません!", "Cannot initialize BGM!")); + /* Cannot enable */ + arg_music = FALSE; + } + + /* Change setting */ + use_music = arg_music; + + if(!arg_music) stop_music(); + else select_floor_music(); + + } + +#endif + + +#ifdef USE_GRAPHICS + + /* Handle "arg_graphics" */ + if (use_graphics != arg_graphics) + { + /* Initialize (if needed) */ + if (arg_graphics && !init_graphics()) + { + /* Warning */ + plog(_("グラフィックスを初期化できません!", "Cannot initialize graphics!")); + + /* Cannot enable */ + arg_graphics = GRAPHICS_NONE; + } + + /* Change setting */ + use_graphics = arg_graphics; + + /* Reset visuals */ +#ifdef ANGBAND_2_8_1 + reset_visuals(); +#else /* ANGBAND_2_8_1 */ + reset_visuals(TRUE); +#endif /* ANGBAND_2_8_1 */ + } + +#endif /* USE_GRAPHICS */ + + + /* Clean up windows */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + term *old = Term; + + term_data *td = &data[i]; + + /* Update resized windows */ + if ((td->cols != td->t.wid) || (td->rows != td->t.hgt)) + { + /* Activate */ + Term_activate(&td->t); + + /* Hack -- Resize the term */ + Term_resize(td->cols, td->rows); + + /* Redraw the contents */ + Term_redraw(); + Term_activate(old); + } + } + + + /* Success */ + return (0); +} + + +/* + * Process at least one event + */ +static errr Term_xtra_win_event(int v) +{ + MSG msg; + + /* Wait for an event */ + if (v) + { + /* Block */ + if (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + /* Check for an event */ + else + { + /* Check */ + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + /* Success */ + return 0; +} + + +/* + * Process all pending events + */ +static errr Term_xtra_win_flush(void) +{ + MSG msg; + + /* Process all pending events */ + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + /* Success */ + return (0); +} + + +/* + * Hack -- clear the screen + * + * Make this more efficient + */ +static errr Term_xtra_win_clear(void) +{ + term_data *td = (term_data*)(Term->data); + + HDC hdc; + RECT rc; + + /* Rectangle to erase */ + rc.left = td->size_ow1; + rc.right = rc.left + td->cols * td->tile_wid; + rc.top = td->size_oh1; + rc.bottom = rc.top + td->rows * td->tile_hgt; + + /* Erase it */ + hdc = GetDC(td->w); + SetBkColor(hdc, RGB(0, 0, 0)); + SelectObject(hdc, td->font_id); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); + + /* bg */ + if (use_bg) + { + rc.left = 0; rc.top = 0; + DrawBG(hdc, &rc); + } + ReleaseDC(td->w, hdc); + + /* Success */ + return 0; +} + + +/* + * Hack -- make a noise + */ +static errr Term_xtra_win_noise(void) +{ + MessageBeep(MB_ICONASTERISK); + return (0); +} + + +/* + * Hack -- make a sound + */ +static errr Term_xtra_win_sound(int v) +{ +#ifdef USE_SOUND + int i; + char buf[1024]; +#endif /* USE_SOUND */ + + /* Sound disabled */ + if (!use_sound) return (1); + + /* Illegal sound */ + if ((v < 0) || (v >= SOUND_MAX)) return (1); + +#ifdef USE_SOUND + + /* Count the samples */ + for (i = 0; i < SAMPLE_MAX; i++) + { + if (!sound_file[v][i]) + break; + } + + /* No sample */ + if (i == 0) return (1); + + /* Build the path */ + path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, sound_file[v][Rand_external(i)]); + +#ifdef WIN32 + + /* Play the sound, catch errors */ + return (PlaySound(buf, 0, SND_FILENAME | SND_ASYNC)); + +#else /* WIN32 */ + + /* Play the sound, catch errors */ + return (sndPlaySound(buf, SND_ASYNC)); + +#endif /* WIN32 */ + +#else /* USE_SOUND */ + + return (1); + +#endif /* USE_SOUND */ +} + +/* + * Hack -- play a music + */ +static errr Term_xtra_win_music(int n, int v) +{ +#ifdef USE_MUSIC + int i = 0; + char buf[1024]; +#endif /* USE_MUSIC */ + + /* Sound disabled */ + + if(!use_music) return (1); + + /* Illegal sound */ + if(n == TERM_XTRA_MUSIC_BASIC && ((v < 0) || (v >= MUSIC_BASIC_MAX))) return (1); + else if(v < 0 || v >= 1000) return(1); /*!< TODO */ + +#ifdef USE_MUSIC + + switch(n) + { + case TERM_XTRA_MUSIC_BASIC: + for (i = 0; i < SAMPLE_MAX; i++) if(!music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_DUNGEON: + for (i = 0; i < SAMPLE_MAX; i++) if(!dungeon_music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_QUEST: + for (i = 0; i < SAMPLE_MAX; i++) if(!quest_music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_TOWN: + for (i = 0; i < SAMPLE_MAX; i++) if(!town_music_file[v][i]) break; + break; + } + + /* No sample */ + if (i == 0) + { + //mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); + //mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); + return (1); + } + + switch(n) + { + case TERM_XTRA_MUSIC_BASIC: + for (i = 0; i < SAMPLE_MAX; i++) if(!music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_DUNGEON: + for (i = 0; i < SAMPLE_MAX; i++) if(!dungeon_music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_QUEST: + for (i = 0; i < SAMPLE_MAX; i++) if(!quest_music_file[v][i]) break; + break; + case TERM_XTRA_MUSIC_TOWN: + for (i = 0; i < SAMPLE_MAX; i++) if(!town_music_file[v][i]) break; + break; + } + + /* No sample */ + if (i == 0) + { + mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); + mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); + return (1); + } + + switch(n) + { + case TERM_XTRA_MUSIC_BASIC: + path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, music_file[v][Rand_external(i)]); + break; + case TERM_XTRA_MUSIC_DUNGEON: + path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, dungeon_music_file[v][Rand_external(i)]); + break; + case TERM_XTRA_MUSIC_QUEST: + path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, quest_music_file[v][Rand_external(i)]); + break; + case TERM_XTRA_MUSIC_TOWN: + path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, town_music_file[v][Rand_external(i)]); + break; + } + + if(current_music_type == n && current_music_id == v) + { + return (0); + } + current_music_type = n; + current_music_id = v; + +#ifdef WIN32 + + mop.lpstrDeviceType = mci_device_type; + mop.lpstrElementName = buf; + mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0); + mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0); + mciSendCommand(mop.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mop); + mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); + mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop); + return (0); + +#endif /* WIN32 */ + +#else /* USE_MUSIC */ + + return (1); + +#endif /* USE_MUSIC */ + +} + + +/* + * Delay for "x" milliseconds + */ +static int Term_xtra_win_delay(int v) +{ + +#ifdef WIN32 + + /* Sleep */ + Sleep(v); + +#else /* WIN32 */ + + DWORD t; + MSG msg; + + /* Final count */ + t = GetTickCount() + v; + + /* Wait for it */ + while (GetTickCount() < t) + { + /* Handle messages */ + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + +#endif /* WIN32 */ + + /* Success */ + return (0); +} + + +/* + * Do a "special thing" + */ +static errr Term_xtra_win(int n, int v) +{ + /* Handle a subset of the legal requests */ + switch (n) + { + /* Make a bell sound */ + case TERM_XTRA_NOISE: + { + return (Term_xtra_win_noise()); + } + + /* Play a music */ + case TERM_XTRA_MUSIC_BASIC: + case TERM_XTRA_MUSIC_DUNGEON: + case TERM_XTRA_MUSIC_QUEST: + case TERM_XTRA_MUSIC_TOWN: + { + return (Term_xtra_win_music(n, v)); + } + + /* Make a special sound */ + case TERM_XTRA_SOUND: + { + return (Term_xtra_win_sound(v)); + } + + /* Process random events */ + case TERM_XTRA_BORED: + { + return (Term_xtra_win_event(0)); + } + + /* Process an event */ + case TERM_XTRA_EVENT: + { + return (Term_xtra_win_event(v)); + } + + /* Flush all events */ + case TERM_XTRA_FLUSH: + { + return (Term_xtra_win_flush()); + } + + /* Clear the screen */ + case TERM_XTRA_CLEAR: + { + return (Term_xtra_win_clear()); + } + + /* React to global changes */ + case TERM_XTRA_REACT: + { + return (Term_xtra_win_react()); + } + + /* Delay for some milliseconds */ + case TERM_XTRA_DELAY: + { + return (Term_xtra_win_delay(v)); + } + } + + return 1; +} + + + +/* + * Low level graphics (Assumes valid input). + * + * Draw a "cursor" at (x,y), using a "yellow box". + */ +static errr Term_curs_win(int x, int y) +{ + term_data *td = (term_data*)(Term->data); + + RECT rc; + HDC hdc; + + int tile_wid, tile_hgt; + + if (td->map_active) + { + tile_wid = td->map_tile_wid; + tile_hgt = td->map_tile_hgt; + } + else + { + tile_wid = td->tile_wid; + tile_hgt = td->tile_hgt; + } + + /* Frame the grid */ + rc.left = x * tile_wid + td->size_ow1; + rc.right = rc.left + tile_wid; + rc.top = y * tile_hgt + td->size_oh1; + rc.bottom = rc.top + tile_hgt; + + /* Cursor is done as a yellow "box" */ + hdc = GetDC(td->w); + FrameRect(hdc, &rc, hbrYellow); + ReleaseDC(td->w, hdc); + + /* Success */ + return 0; +} + + +/* + * Low level graphics (Assumes valid input). + * + * Draw a "big cursor" at (x,y), using a "yellow box". + */ +static errr Term_bigcurs_win(int x, int y) +{ + term_data *td = (term_data*)(Term->data); + + RECT rc; + HDC hdc; + + int tile_wid, tile_hgt; + + if (td->map_active) + { + /* Normal cursor in map window */ + Term_curs_win(x, y); + return 0; + } + else + { + tile_wid = td->tile_wid; + tile_hgt = td->tile_hgt; + } + + /* Frame the grid */ + rc.left = x * tile_wid + td->size_ow1; + rc.right = rc.left + 2 * tile_wid; + rc.top = y * tile_hgt + td->size_oh1; + rc.bottom = rc.top + tile_hgt; + + /* Cursor is done as a yellow "box" */ + hdc = GetDC(td->w); + FrameRect(hdc, &rc, hbrYellow); + ReleaseDC(td->w, hdc); + + /* Success */ + return 0; +} + + +/* + * Low level graphics (Assumes valid input). + * + * Erase a "block" of "n" characters starting at (x,y). + */ +static errr Term_wipe_win(int x, int y, int n) +{ + term_data *td = (term_data*)(Term->data); + + HDC hdc; + RECT rc; + + /* Rectangle to erase in client coords */ + rc.left = x * td->tile_wid + td->size_ow1; + rc.right = rc.left + n * td->tile_wid; + rc.top = y * td->tile_hgt + td->size_oh1; + rc.bottom = rc.top + td->tile_hgt; + + hdc = GetDC(td->w); + SetBkColor(hdc, RGB(0, 0, 0)); + SelectObject(hdc, td->font_id); + /* bg */ + if (use_bg) + DrawBG(hdc, &rc); + else + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); + ReleaseDC(td->w, hdc); + + /* Success */ + return 0; +} + + +/* + * Low level graphics. Assumes valid input. + * + * Draw several ("n") chars, with an attr, at a given location. + * + * All "graphic" data is handled by "Term_pict_win()", below. + * + * One would think there is a more efficient method for telling a window + * what color it should be using to draw with, but perhaps simply changing + * it every time is not too inefficient. + */ +static errr Term_text_win(int x, int y, int n, TERM_COLOR a, concptr s) +{ + term_data *td = (term_data*)(Term->data); + RECT rc; + HDC hdc; + +#if 1 /* #ifdef JP */ + static HBITMAP WALL; + static HBRUSH myBrush, oldBrush; + static HPEN oldPen; + static bool init_done = FALSE; + + if (!init_done){ + WALL = LoadBitmap(hInstance, AppName); + myBrush = CreatePatternBrush(WALL); + init_done = TRUE; + } +#endif + + /* Total rectangle */ + rc.left = x * td->tile_wid + td->size_ow1; + rc.right = rc.left + n * td->tile_wid; + rc.top = y * td->tile_hgt + td->size_oh1; + rc.bottom = rc.top + td->tile_hgt; + + /* Acquire DC */ + hdc = GetDC(td->w); + + /* Background color */ + SetBkColor(hdc, RGB(0, 0, 0)); + + /* Foreground color */ + if (colors16) + { + SetTextColor(hdc, PALETTEINDEX(win_pal[a])); + } + else if (paletted) + { + SetTextColor(hdc, win_clr[a&0x0F]); + } + else + { + SetTextColor(hdc, win_clr[a]); + } + + /* Use the font */ + SelectObject(hdc, td->font_id); + + /* bg */ + if (use_bg) SetBkMode(hdc, TRANSPARENT); + + /* Bizarre size */ + if (td->bizarre || + (td->tile_hgt != td->font_hgt) || + (td->tile_wid != td->font_wid)) + { + int i; + + /* Erase complete rectangle */ + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); + + /* bg */ + if (use_bg) DrawBG(hdc, &rc); + + /* New rectangle */ + rc.left += ((td->tile_wid - td->font_wid) / 2); + rc.right = rc.left + td->font_wid; + rc.top += ((td->tile_hgt - td->font_hgt) / 2); + rc.bottom = rc.top + td->font_hgt; + + /* Dump each character */ + for (i = 0; i < n; i++) + { +#ifdef JP + if (use_bigtile && *(s+i)=="■"[0] && *(s+i+1)=="■"[1]) + { + rc.right += td->font_wid; + + oldBrush = SelectObject(hdc, myBrush); + oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); + + /* Dump the wall */ + Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); + + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + rc.right -= td->font_wid; + + /* Advance */ + i++; + rc.left += 2 * td->tile_wid; + rc.right += 2 * td->tile_wid; + } + else if ( iskanji(*(s+i)) ) /* 2バイト文字 */ + { + rc.right += td->font_wid; + /* Dump the text */ + ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, + s+i, 2, NULL); + rc.right -= td->font_wid; + + /* Advance */ + i++; + rc.left += 2 * td->tile_wid; + rc.right += 2 * td->tile_wid; + } else if (*(s+i)==127){ + oldBrush = SelectObject(hdc, myBrush); + oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); + + /* Dump the wall */ + Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); + + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + + /* Advance */ + rc.left += td->tile_wid; + rc.right += td->tile_wid; + } else { + /* Dump the text */ + ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, s+i, 1, NULL); + + /* Advance */ + rc.left += td->tile_wid; + rc.right += td->tile_wid; + } +#else +#if 1 + if (*(s+i)==127){ + oldBrush = SelectObject(hdc, myBrush); + oldPen = SelectObject(hdc, GetStockObject(NULL_PEN) ); + + /* Dump the wall */ + Rectangle(hdc, rc.left, rc.top, rc.right+1, rc.bottom+1); + + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + + /* Advance */ + rc.left += td->tile_wid; + rc.right += td->tile_wid; + } else { + /* Dump the text */ + ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, + s+i, 1, NULL); + + /* Advance */ + rc.left += td->tile_wid; + rc.right += td->tile_wid; + } +#else + /* Dump the text */ + ExtTextOut(hdc, rc.left, rc.top, 0, &rc, + s+i, 1, NULL); + + /* Advance */ + rc.left += td->tile_wid; + rc.right += td->tile_wid; +#endif +#endif + + } + } + + /* Normal size */ + else + { + /* Dump the text */ + ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED, &rc, + s, n, NULL); + } + + /* Release DC */ + ReleaseDC(td->w, hdc); + + /* Success */ + return 0; +} + + +/* + * Low level graphics. Assumes valid input. + * + * Draw an array of "special" attr/char pairs at the given location. + * + * We use the "Term_pict_win()" function for "graphic" data, which are + * encoded by setting the "high-bits" of both the "attr" and the "char" + * data. We use the "attr" to represent the "row" of the main bitmap, + * and the "char" to represent the "col" of the main bitmap. The use + * of this function is induced by the "higher_pict" flag. + * + * If "graphics" is not available, we simply "wipe" the given grids. + */ +static errr Term_pict_win(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, concptr cp, const TERM_COLOR *tap, concptr tcp) +{ + term_data *td = (term_data*)(Term->data); + +#ifdef USE_GRAPHICS + + int i; + TERM_LEN x1, y1, w1, h1, tw1, th1; + TERM_LEN x2, y2, w2, h2, tw2 = 0; + TERM_LEN x3, y3; + + HDC hdcMask = NULL; + + HDC hdc; + HDC hdcSrc; + HBITMAP hbmSrcOld; + + /* Paranoia */ + if (!use_graphics) + { + /* Erase the grids */ + return (Term_wipe_win(x, y, n)); + } + + /* Size of bitmap cell */ + w1 = infGraph.CellWidth; + h1 = infGraph.CellHeight; + tw1 = infGraph.TileWidth; + th1 = infGraph.TileHeight; + + /* Size of window cell */ + if (td->map_active) + { + w2 = td->map_tile_wid; + h2 = td->map_tile_hgt; + } + else + { + w2 = td->tile_wid; + h2 = td->tile_hgt; + tw2 = w2; + + /* big tile mode */ + if (use_bigtile) tw2 *= 2; + } + + /* Location of window cell */ + x2 = x * w2 + td->size_ow1 + infGraph.OffsetX; + y2 = y * h2 + td->size_oh1 + infGraph.OffsetY; + + /* Info */ + hdc = GetDC(td->w); + + /* More info */ + hdcSrc = CreateCompatibleDC(hdc); + hbmSrcOld = SelectObject(hdcSrc, infGraph.hBitmap); + + if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) + { + hdcMask = CreateCompatibleDC(hdc); + SelectObject(hdcMask, infMask.hBitmap); + } + + /* Draw attr/char pairs */ + for (i = 0; i < n; i++, x2 += w2) + { + TERM_COLOR a = ap[i]; + char c = cp[i]; + + + /* Extract picture */ + int row = (a & 0x7F); + int col = (c & 0x7F); + + /* Location of bitmap cell */ + x1 = col * w1; + y1 = row * h1; + + if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) + { + x3 = (tcp[i] & 0x7F) * w1; + y3 = (tap[i] & 0x7F) * h1; + tw2 = tw2 * w1 / tw1; + h2 = h2 * h1 / th1; + + /* Perfect size */ + if ((tw1 == tw2) && (th1 == h2)) + { + /* Copy the terrain picture from the bitmap to the window */ + BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, SRCCOPY); + + /* Mask out the tile */ + BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, SRCAND); + + /* Draw the tile */ + BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCPAINT); + } + + /* Need to stretch */ + else + { + /* Set the correct mode for stretching the tiles */ + SetStretchBltMode(hdc, COLORONCOLOR); + + /* Copy the terrain picture from the bitmap to the window */ + StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x3, y3, w1, h1, SRCAND); + + StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, w1, h1, SRCPAINT); + + /* Only draw if terrain and overlay are different */ + if ((x1 != x3) || (y1 != y3)) + { + /* Mask out the tile */ + StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, w1, h1, SRCAND); + + /* Draw the tile */ + StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCPAINT); + } + } + } + else + { + /* Perfect size */ + if ((w1 == tw2) && (h1 == h2)) + { + /* Copy the picture from the bitmap to the window */ + BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCCOPY); + } + + /* Need to stretch */ + else + { + /* Set the correct mode for stretching the tiles */ + SetStretchBltMode(hdc, COLORONCOLOR); + + /* Copy the picture from the bitmap to the window */ + StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCCOPY); + } + } + } + + /* Release */ + SelectObject(hdcSrc, hbmSrcOld); + DeleteDC(hdcSrc); + + if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) + { + /* Release */ + SelectObject(hdcMask, hbmSrcOld); + DeleteDC(hdcMask); + } + + /* Release */ + ReleaseDC(td->w, hdc); + +#else /* USE_GRAPHICS */ + + /* Just erase this grid */ + return (Term_wipe_win(x, y, n)); + +#endif /* USE_GRAPHICS */ + + /* Success */ + return 0; +} + + +static void windows_map(void) +{ + term_data *td = &data[0]; + TERM_COLOR a; + char c; + TERM_LEN x, min_x, max_x; + TERM_LEN y, min_y, max_y; + + TERM_COLOR ta; + char tc; + + /* Only in graphics mode */ + if (!use_graphics) return; + Term_xtra_win_clear(); + + td->map_tile_wid = (td->tile_wid * td->cols) / MAX_WID; + td->map_tile_hgt = (td->tile_hgt * td->rows) / MAX_HGT; + td->map_active = TRUE; + + { + min_x = 0; + min_y = 0; + max_x = cur_wid; + max_y = cur_hgt; + } + + /* Draw the map */ + for (x = min_x; x < max_x; x++) + { + for (y = min_y; y < max_y; y++) + { + map_info(y, x, &a, (char*)&c, &ta, (char*)&tc); + + /* Ignore non-graphics */ + if ((a & 0x80) && (c & 0x80)) + { + Term_pict_win(x - min_x, y - min_y, 1, &a, &c, &ta, &tc); + } + } + } + + /* Hilite the player */ + Term_curs_win(p_ptr->x - min_x, p_ptr->y - min_y); + + /* Wait for a keypress, flush key buffer */ + Term_inkey(&c, TRUE, TRUE); + Term_flush(); + + /* Switch off the map display */ + td->map_active = FALSE; + + /* Restore screen */ + Term_xtra_win_clear(); + Term_redraw(); +} + + +/*** Other routines ***/ + + +/* + * Create and initialize a "term_data" given a title + */ +static void term_data_link(term_data *td) +{ + term *t = &td->t; + + /* Initialize the term */ + term_init(t, td->cols, td->rows, td->keys); + + /* Use a "software" cursor */ + t->soft_cursor = TRUE; + + /* Use "Term_pict" for "graphic" data */ + t->higher_pict = TRUE; + + /* Erase with "white space" */ + t->attr_blank = TERM_WHITE; + t->char_blank = ' '; + +#if 0 + /* Prepare the init/nuke hooks */ + t->init_hook = Term_init_win; + t->nuke_hook = Term_nuke_win; +#endif + + /* Prepare the template hooks */ + t->user_hook = Term_user_win; + t->xtra_hook = Term_xtra_win; + t->curs_hook = Term_curs_win; + t->bigcurs_hook = Term_bigcurs_win; + t->wipe_hook = Term_wipe_win; + t->text_hook = Term_text_win; + t->pict_hook = Term_pict_win; + + /* Remember where we came from */ + t->data = (vptr)(td); +} + + +/* + * Create the windows + * + * First, instantiate the "default" values, then read the "ini_file" + * to over-ride selected values, then create the windows, and fonts. + * + * Must use SW_SHOW not SW_SHOWNA, since on 256 color display + * must make active to realize the palette. + */ +static void init_windows(void) +{ + int i; + + term_data *td; + +#if 0 /* #ifndef JP */ + char buf[1024]; +#endif + + /* Main window */ + td = &data[0]; + WIPE(td, term_data); +#ifdef JP + td->s = "変愚蛮怒"; +#else + td->s = angband_term_name[0]; +#endif + + td->keys = 1024; + td->rows = 24; + td->cols = 80; + td->visible = TRUE; + td->size_ow1 = 2; + td->size_ow2 = 2; + td->size_oh1 = 2; + td->size_oh2 = 2; + td->pos_x = 7 * 30; + td->pos_y = 7 * 20; + td->posfix = FALSE; +#if 1 /* #ifdef JP */ + td->bizarre = TRUE; +#endif + /* Sub windows */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + td = &data[i]; + WIPE(td, term_data); + td->s = angband_term_name[i]; + td->keys = 16; + td->rows = 24; + td->cols = 80; + td->visible = FALSE; + td->size_ow1 = 1; + td->size_ow2 = 1; + td->size_oh1 = 1; + td->size_oh2 = 1; + td->pos_x = (7 - i) * 30; + td->pos_y = (7 - i) * 20; + td->posfix = FALSE; +#if 1 /* #ifdef JP */ + td->bizarre = TRUE; +#endif + } + + + /* Load prefs */ + load_prefs(); + + + /* Main window (need these before term_getsize gets called) */ + td = &data[0]; + td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | + WS_VISIBLE); + td->dwExStyle = 0; + td->visible = TRUE; + + /* Sub windows (need these before term_getsize gets called) */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + td = &data[i]; + td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU); + td->dwExStyle = (WS_EX_TOOLWINDOW); + } + + + /* All windows */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + td = &data[i]; + +#if 1 /* #ifdef JP */ + strncpy(td->lf.lfFaceName, td->font_want, LF_FACESIZE); + td->lf.lfCharSet = DEFAULT_CHARSET; + td->lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; + /* Activate the chosen font */ + term_force_font(td, NULL); + if(!td->tile_wid) td->tile_wid = td->font_wid; + if(!td->tile_hgt) td->tile_hgt = td->font_hgt; +#else + /* Access the standard font file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_FONT, td->font_want); + + /* Activate the chosen font */ + if (term_force_font(td, buf)) + { + /* Access the standard font file */ + path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); + + /* Force the use of that font */ + (void)term_force_font(td, buf); + + td->tile_wid = 8; + td->tile_hgt = 13; + + /* Assume not bizarre */ + td->bizarre = FALSE; + } +#endif + + + /* Analyze the font */ + term_getsize(td); + + /* Resize the window */ + term_window_resize(td); + } + + + /* Sub windows (reverse order) */ + for (i = MAX_TERM_DATA - 1; i >= 1; --i) + { + td = &data[i]; + + my_td = td; + td->w = CreateWindowEx(td->dwExStyle, AngList, + td->s, td->dwStyle, + td->pos_x, td->pos_y, + td->size_wid, td->size_hgt, + HWND_DESKTOP, NULL, hInstance, NULL); + my_td = NULL; + if (!td->w) quit(_("サブウィンドウに作成に失敗しました", "Failed to create sub-window")); + + if (td->visible) + { + td->size_hack = TRUE; + ShowWindow(td->w, SW_SHOW); + td->size_hack = FALSE; + } + + term_data_link(td); + angband_term[i] = &td->t; + + if (td->visible) + { + /* Activate the window */ + SetActiveWindow(td->w); + } + + if (data[i].posfix) + { + term_window_pos(&data[i], HWND_TOPMOST); + } + else + { + term_window_pos(&data[i], td->w); + } + } + + + /* Main window */ + td = &data[0]; + + /* Main window */ + my_td = td; + td->w = CreateWindowEx(td->dwExStyle, AppName, + td->s, td->dwStyle, + td->pos_x, td->pos_y, + td->size_wid, td->size_hgt, + HWND_DESKTOP, NULL, hInstance, NULL); + my_td = NULL; + if (!td->w) quit(_("メインウィンドウの作成に失敗しました", "Failed to create Angband window")); + + term_data_link(td); + angband_term[0] = &td->t; + normsize.x = td->cols; + normsize.y = td->rows; + + /* Activate the main window */ + if (win_maximized) ShowWindow(td->w, SW_SHOWMAXIMIZED); + else ShowWindow(td->w, SW_SHOW); + + /* Bring main window back to top */ + SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + + + /* New palette */ + (void)new_palette(); + + + /* Create a "brush" for drawing the "cursor" */ + hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]); + + + /* Process pending messages */ + (void)Term_xtra_win_flush(); +} + + + +/* + * Prepare the menus + */ +static void setup_menus(void) +{ + int i; + + HMENU hm = GetMenu(data[0].w); + + + /* Menu "File", Disable all */ + EnableMenuItem(hm, IDM_FILE_NEW, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_FILE_OPEN, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_FILE_SAVE, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_FILE_EXIT, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_FILE_SCORE, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + + /* No character available */ + if (!character_generated) + { + /* Menu "File", Item "New" */ + EnableMenuItem(hm, IDM_FILE_NEW, MF_BYCOMMAND | MF_ENABLED); + + /* Menu "File", Item "Open" */ + EnableMenuItem(hm, IDM_FILE_OPEN, MF_BYCOMMAND | MF_ENABLED); + } + + /* A character available */ + if (character_generated) + { + /* Menu "File", Item "Save" */ + EnableMenuItem(hm, IDM_FILE_SAVE, + MF_BYCOMMAND | MF_ENABLED); + } + + /* Menu "File", Item "Exit" */ + EnableMenuItem(hm, IDM_FILE_EXIT, + MF_BYCOMMAND | MF_ENABLED); + + EnableMenuItem(hm, IDM_FILE_SCORE, + MF_BYCOMMAND | MF_ENABLED); + + + /* Menu "Window::Visibility" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i, + (data[i].visible ? MF_CHECKED : MF_UNCHECKED)); + + EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, + MF_BYCOMMAND | MF_ENABLED); + } + + /* Menu "Window::Font" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, + MF_BYCOMMAND | MF_ENABLED); + } + } + + /* Menu "Window::Window Position Fix" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + CheckMenuItem(hm, IDM_WINDOW_POS_0 + i, + (data[i].posfix ? MF_CHECKED : MF_UNCHECKED)); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, + MF_BYCOMMAND | MF_ENABLED); + } + } + + /* Menu "Window::Bizarre Display" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + CheckMenuItem(hm, IDM_WINDOW_BIZ_0 + i, + (data[i].bizarre ? MF_CHECKED : MF_UNCHECKED)); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_BIZ_0 + i, + MF_BYCOMMAND | MF_ENABLED); + + } + } + + /* Menu "Window::Increase Tile Width" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, + MF_BYCOMMAND | MF_ENABLED); + + } + } + + /* Menu "Window::Decrease Tile Width" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, + MF_BYCOMMAND | MF_ENABLED); + + } + } + + /* Menu "Window::Increase Tile Height" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, + MF_BYCOMMAND | MF_ENABLED); + + } + } + + /* Menu "Window::Decrease Tile Height" */ + for (i = 0; i < MAX_TERM_DATA; i++) + { + EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + if (data[i].visible) + { + EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, + MF_BYCOMMAND | MF_ENABLED); + + } + } + + /* Menu "Options", disable all */ + EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hm, IDM_OPTIONS_SOUND, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); +#ifndef JP + EnableMenuItem(hm, IDM_OPTIONS_SAVER, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); +#endif + + /* Menu "Options", Item "Map" */ + if (use_graphics != GRAPHICS_NONE) + EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP, MF_BYCOMMAND | MF_ENABLED); + else + EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP, + MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + + /* Menu "Options", update all */ + CheckMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, + (arg_graphics == GRAPHICS_NONE ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, + (arg_graphics == GRAPHICS_ORIGINAL ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, + (arg_graphics == GRAPHICS_ADAM_BOLT ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_NEW2_GRAPHICS, + (arg_graphics == GRAPHICS_HENGBAND ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_BIGTILE, + (arg_bigtile ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_MUSIC, + (arg_music ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_SOUND, + (arg_sound ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(hm, IDM_OPTIONS_BG, + (use_bg ? MF_CHECKED : MF_UNCHECKED)); +#ifndef JP + CheckMenuItem(hm, IDM_OPTIONS_SAVER, + (hwndSaver ? MF_CHECKED : MF_UNCHECKED)); +#endif + +#ifdef USE_GRAPHICS + /* Menu "Options", Item "Graphics" */ + EnableMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, MF_ENABLED); + /* Menu "Options", Item "Graphics" */ + EnableMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, MF_ENABLED); + /* Menu "Options", Item "Graphics" */ + EnableMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, MF_ENABLED); + /* Menu "Options", Item "Graphics" */ + EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_ENABLED); +#endif /* USE_GRAPHICS */ + +#ifdef USE_SOUND + /* Menu "Options", Item "Sound" */ + EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_ENABLED); +#endif /* USE_SOUND */ + +#ifdef USE_SAVER + /* Menu "Options", Item "ScreenSaver" */ + EnableMenuItem(hm, IDM_OPTIONS_SAVER, + MF_BYCOMMAND | MF_ENABLED); +#endif /* USE_SAVER */ +} + + +/* + * Check for double clicked (or dragged) savefile + * + * Apparently, Windows copies the entire filename into the first + * piece of the "command line string". Perhaps we should extract + * the "basename" of that filename and append it to the "save" dir. + */ +static void check_for_save_file(LPSTR cmd_line) +{ + char *s; + + /* First arg */ + s = cmd_line; + + /* No args */ + if (!*s) return; + + /* Extract filename */ + strcat(savefile, s); + + /* Validate the file */ + validate_file(savefile); + + /* Game in progress */ + game_in_progress = TRUE; + + /* Play game */ + play_game(FALSE); +} + + +/* + * Process a menu command + */ +static void process_menus(WORD wCmd) +{ + int i; + + term_data *td; + + OPENFILENAME ofn; + + /* Analyze */ + switch (wCmd) + { + /* New game */ + case IDM_FILE_NEW: + { + if (!initialized) + { + plog(_("まだ初期化中です...", "You cannot do that yet...")); + } + else if (game_in_progress) + { + plog(_("プレイ中は新しいゲームを始めることができません!", "You can't start a new game while you're still playing!")); + } + else + { + game_in_progress = TRUE; + Term_flush(); + play_game(TRUE); + quit(NULL); + } + break; + } + + /* Open game */ + case IDM_FILE_OPEN: + { + if (!initialized) + { + plog(_("まだ初期化中です...", "You cannot do that yet...")); + } + else if (game_in_progress) + { + plog(_("プレイ中はゲームをロードすることができません!", "You can't open a new game while you're still playing!")); + } + else + { + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = data[0].w; + ofn.lpstrFilter = "Save Files (*.)\0*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = savefile; + ofn.nMaxFile = 1024; + ofn.lpstrInitialDir = ANGBAND_DIR_SAVE; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; + + if (GetOpenFileName(&ofn)) + { + /* Load 'savefile' */ + validate_file(savefile); + game_in_progress = TRUE; + Term_flush(); + play_game(FALSE); + quit(NULL); + } + } + break; + } + + /* Save game */ + case IDM_FILE_SAVE: + { + if (game_in_progress && character_generated) + { + /* Paranoia */ + if (!can_save) + { + plog(_("今はセーブすることは出来ません。", "You may not do that right now.")); + break; + } + + /* Hack -- Forget messages */ + msg_flag = FALSE; + + /* Save the game */ +#ifdef ZANGBAND + do_cmd_save_game(FALSE); +#else /* ZANGBAND */ + do_cmd_save_game(); +#endif /* ZANGBAND */ + } + else + { + plog(_("今、セーブすることは出来ません。", "You may not do that right now.")); + } + break; + } + + /* Exit */ + case IDM_FILE_EXIT: + { + if (game_in_progress && character_generated) + { + /* Paranoia */ + if (!can_save) + { + plog(_("今は終了できません。", "You may not do that right now.")); + break; + } + + /* Hack -- Forget messages */ + msg_flag = FALSE; + + forget_lite(); + forget_view(); + clear_mon_lite(); + + /* Save the game */ +#ifdef ZANGBAND + /* do_cmd_save_game(FALSE); */ +#else /* ZANGBAND */ + /* do_cmd_save_game(); */ +#endif /* ZANGBAND */ + Term_key_push(SPECIAL_KEY_QUIT); + break; + } + quit(NULL); + break; + } + + /* Show scores */ + case IDM_FILE_SCORE: + { + char buf[1024]; + + /* Build the filename */ + path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); + + /* Open the binary high score file, for reading */ + highscore_fd = fd_open(buf, O_RDONLY); + + /* Paranoia -- No score file */ + if (highscore_fd < 0) + { + msg_print("Score file unavailable."); + } + else + { + screen_save(); + Term_clear(); + + /* Display the scores */ + display_scores_aux(0, MAX_HISCORES, -1, NULL); + + /* Shut the high score file */ + (void)fd_close(highscore_fd); + + /* Forget the high score fd */ + highscore_fd = -1; + screen_load(); + + /* Hack - Flush it */ + Term_fresh(); + } + + break; + } + + /* Open game */ + case IDM_FILE_MOVIE: + { + if (!initialized) + { + plog(_("まだ初期化中です...", "You cannot do that yet...")); + } + else if (game_in_progress) + { + plog(_("プレイ中はムービーをロードすることができません!", "You can't open a movie while you're playing!")); + } + else + { + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = data[0].w; + ofn.lpstrFilter = "Angband Movie Files (*.amv)\0*.amv\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = savefile; + ofn.nMaxFile = 1024; + ofn.lpstrInitialDir = ANGBAND_DIR_USER; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + + if (GetOpenFileName(&ofn)) + { + /* Load 'savefile' */ + prepare_browse_movie_aux(savefile); + play_game(FALSE); + quit(NULL); + return; + } + } + break; + } + + + case IDM_WINDOW_VIS_0: + { + plog(_("メインウィンドウは非表示にできません!", "You are not allowed to do that!")); + break; + } + + /* Window visibility */ + case IDM_WINDOW_VIS_1: + case IDM_WINDOW_VIS_2: + case IDM_WINDOW_VIS_3: + case IDM_WINDOW_VIS_4: + case IDM_WINDOW_VIS_5: + case IDM_WINDOW_VIS_6: + case IDM_WINDOW_VIS_7: + { + i = wCmd - IDM_WINDOW_VIS_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + if (!td->visible) + { + td->visible = TRUE; + ShowWindow(td->w, SW_SHOW); + term_data_redraw(td); + } + else + { + td->visible = FALSE; + td->posfix = FALSE; + ShowWindow(td->w, SW_HIDE); + } + + break; + } + + /* Window fonts */ + case IDM_WINDOW_FONT_0: + case IDM_WINDOW_FONT_1: + case IDM_WINDOW_FONT_2: + case IDM_WINDOW_FONT_3: + case IDM_WINDOW_FONT_4: + case IDM_WINDOW_FONT_5: + case IDM_WINDOW_FONT_6: + case IDM_WINDOW_FONT_7: + { + i = wCmd - IDM_WINDOW_FONT_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + term_change_font(td); + + break; + } + + /* Window Z Position */ + case IDM_WINDOW_POS_1: + case IDM_WINDOW_POS_2: + case IDM_WINDOW_POS_3: + case IDM_WINDOW_POS_4: + case IDM_WINDOW_POS_5: + case IDM_WINDOW_POS_6: + case IDM_WINDOW_POS_7: + { + i = wCmd - IDM_WINDOW_POS_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + if (!td->posfix && td->visible) + { + td->posfix = TRUE; + term_window_pos(td, HWND_TOPMOST); + } + else + { + td->posfix = FALSE; + term_window_pos(td, data[0].w); + } + + break; + } + + /* Bizarre Display */ + case IDM_WINDOW_BIZ_0: + case IDM_WINDOW_BIZ_1: + case IDM_WINDOW_BIZ_2: + case IDM_WINDOW_BIZ_3: + case IDM_WINDOW_BIZ_4: + case IDM_WINDOW_BIZ_5: + case IDM_WINDOW_BIZ_6: + case IDM_WINDOW_BIZ_7: + { + i = wCmd - IDM_WINDOW_BIZ_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + td->bizarre = !td->bizarre; + + term_getsize(td); + + term_window_resize(td); + + break; + } + + /* Increase Tile Width */ + case IDM_WINDOW_I_WID_0: + case IDM_WINDOW_I_WID_1: + case IDM_WINDOW_I_WID_2: + case IDM_WINDOW_I_WID_3: + case IDM_WINDOW_I_WID_4: + case IDM_WINDOW_I_WID_5: + case IDM_WINDOW_I_WID_6: + case IDM_WINDOW_I_WID_7: + { + i = wCmd - IDM_WINDOW_I_WID_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + td->tile_wid += 1; + + term_getsize(td); + + term_window_resize(td); + + break; + } + + /* Decrease Tile Height */ + case IDM_WINDOW_D_WID_0: + case IDM_WINDOW_D_WID_1: + case IDM_WINDOW_D_WID_2: + case IDM_WINDOW_D_WID_3: + case IDM_WINDOW_D_WID_4: + case IDM_WINDOW_D_WID_5: + case IDM_WINDOW_D_WID_6: + case IDM_WINDOW_D_WID_7: + { + i = wCmd - IDM_WINDOW_D_WID_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + td->tile_wid -= 1; + + term_getsize(td); + + term_window_resize(td); + + break; + } + + /* Increase Tile Height */ + case IDM_WINDOW_I_HGT_0: + case IDM_WINDOW_I_HGT_1: + case IDM_WINDOW_I_HGT_2: + case IDM_WINDOW_I_HGT_3: + case IDM_WINDOW_I_HGT_4: + case IDM_WINDOW_I_HGT_5: + case IDM_WINDOW_I_HGT_6: + case IDM_WINDOW_I_HGT_7: + { + i = wCmd - IDM_WINDOW_I_HGT_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + td->tile_hgt += 1; + + term_getsize(td); + + term_window_resize(td); + + break; + } + + /* Decrease Tile Height */ + case IDM_WINDOW_D_HGT_0: + case IDM_WINDOW_D_HGT_1: + case IDM_WINDOW_D_HGT_2: + case IDM_WINDOW_D_HGT_3: + case IDM_WINDOW_D_HGT_4: + case IDM_WINDOW_D_HGT_5: + case IDM_WINDOW_D_HGT_6: + case IDM_WINDOW_D_HGT_7: + { + i = wCmd - IDM_WINDOW_D_HGT_0; + + if ((i < 0) || (i >= MAX_TERM_DATA)) break; + + td = &data[i]; + + td->tile_hgt -= 1; + + term_getsize(td); + + term_window_resize(td); + + break; + } + + case IDM_OPTIONS_NO_GRAPHICS: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_graphics" */ + if (arg_graphics != GRAPHICS_NONE) + { + arg_graphics = GRAPHICS_NONE; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + } + + break; + } + + case IDM_OPTIONS_OLD_GRAPHICS: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_graphics" */ + if (arg_graphics != GRAPHICS_ORIGINAL) + { + arg_graphics = GRAPHICS_ORIGINAL; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + } + + break; + } + + case IDM_OPTIONS_NEW_GRAPHICS: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_graphics" */ + if (arg_graphics != GRAPHICS_ADAM_BOLT) + { + arg_graphics = GRAPHICS_ADAM_BOLT; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + } + + break; + } + + case IDM_OPTIONS_NEW2_GRAPHICS: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_graphics" */ + if (arg_graphics != GRAPHICS_HENGBAND) + { + arg_graphics = GRAPHICS_HENGBAND; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + } + + break; + } + + case IDM_OPTIONS_BIGTILE: + { + td = &data[0]; + + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_sound" */ + arg_bigtile = !arg_bigtile; + + /* Activate */ + Term_activate(&td->t); + + /* Resize the term */ + Term_resize(td->cols, td->rows); + + /* Redraw later */ + InvalidateRect(td->w, NULL, TRUE); + + break; + } + + case IDM_OPTIONS_MUSIC: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_sound" */ + arg_music = !arg_music; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + + break; + } + + case IDM_OPTIONS_SOUND: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "arg_sound" */ + arg_sound = !arg_sound; + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + + break; + } + + /* bg */ + case IDM_OPTIONS_BG: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + + /* Toggle "use_bg" */ + use_bg = !use_bg; + + init_bg(); + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + + break; + } + + /* bg */ + case IDM_OPTIONS_OPEN_BG: + { + /* Paranoia */ + if (!inkey_flag) + { + plog("You may not do that right now."); + break; + } + else + { + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = data[0].w; + ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = bg_bitmap_file; + ofn.nMaxFile = 1023; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = _("壁紙を選んでね。", "Choose wall paper."); + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&ofn)) + { + /* Load 'savefile' */ + use_bg = 1; + init_bg(); + } + + /* React to changes */ + Term_xtra_win_react(); + + /* Hack -- Force redraw */ + Term_key_push(KTRL('R')); + } + break; + } + + case IDM_DUMP_SCREEN_HTML: + { + static char buf[1024] = ""; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = data[0].w; + ofn.lpstrFilter = "HTML Files (*.html)\0*.html\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = buf; + ofn.nMaxFile = 1023; + ofn.lpstrDefExt = "html"; + ofn.lpstrInitialDir = NULL; + ofn.lpstrTitle = _("HTMLでスクリーンダンプを保存", "Save screen dump as HTML."); + ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + + if (GetSaveFileName(&ofn)) + { + do_cmd_save_screen_html_aux(buf, 0); + } + break; + } + +#ifdef USE_SAVER + + case IDM_OPTIONS_SAVER: + { + if (hwndSaver) + { + DestroyWindow(hwndSaver); + hwndSaver = NULL; + } + else + { + /* Create a screen scaver window */ + hwndSaver = CreateWindowEx(WS_EX_TOPMOST, "WindowsScreenSaverClass", + "Angband Screensaver", + WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, + 0, 0, GetSystemMetrics(SM_CXSCREEN), + GetSystemMetrics(SM_CYSCREEN), + NULL, NULL, hInstance, NULL); + + if (hwndSaver) + { + /* Push the window to the bottom */ + SetWindowPos(hwndSaver, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + else + { + plog(_("ウィンドウを作成出来ません", "Failed to create saver window")); + } + } + break; + } + +#endif + + case IDM_OPTIONS_MAP: + { + windows_map(); + break; + } + + case IDM_HELP_CONTENTS: + { +#ifdef HTML_HELP + char tmp[1024]; + path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_HELP, "zangband.chm"); + if (check_file(tmp)) + { + HtmlHelp(data[0].w, tmp, HH_DISPLAY_TOPIC, 0); + } + else + { + plog_fmt(_("ヘルプファイル[%s]が見付かりません。", "Cannot find help file: %s"), tmp); + plog(_("代わりにオンラインヘルプを使用してください。", "Use the online help files instead.")); + } + break; +#else /* HTML_HELP */ + char buf[1024]; + char tmp[1024]; + path_build(tmp, sizeof(tmp), ANGBAND_DIR_XTRA_HELP, "zangband.hlp"); + if (check_file(tmp)) + { + sprintf(buf, "winhelp.exe %s", tmp); + WinExec(buf, SW_NORMAL); + } + else + { + plog_fmt(_("ヘルプファイル[%s]が見付かりません。", "Cannot find help file: %s"), tmp); + plog(_("代わりにオンラインヘルプを使用してください。", "Use the online help files instead.")); + + } + break; +#endif /* HTML_HELP */ + } + } +} + + +static bool process_keydown(WPARAM wParam, LPARAM lParam) +{ + int i; + bool mc = FALSE; + bool ms = FALSE; + bool ma = FALSE; + + /* Extract the modifiers */ + if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE; + if (GetKeyState(VK_SHIFT) & 0x8000) ms = TRUE; + if (GetKeyState(VK_MENU) & 0x8000) ma = TRUE; + + Term_no_press = (ma) ? TRUE : FALSE; + + /* Handle "special" keys */ + if (special_key[(byte)(wParam)] || (ma && !ignore_key[(byte)(wParam)]) ) + { + bool ext_key = (lParam & 0x1000000L) ? TRUE : FALSE; + bool numpad = FALSE; + + /* Begin the macro trigger */ + Term_keypress(31); + + /* Send the modifiers */ + if (mc) Term_keypress('C'); + if (ms) Term_keypress('S'); + if (ma) Term_keypress('A'); + + /* Extract "scan code" */ + i = LOBYTE(HIWORD(lParam)); + + /* Introduce the scan code */ + Term_keypress('x'); + + /* Extended key bit */ + switch (wParam) + { + /* Numpad Enter and '/' are extended key */ + case VK_DIVIDE: + Term_no_press = TRUE; + case VK_RETURN: /* Enter */ + numpad = ext_key; + break; + /* Other extended keys are on full keyboard */ + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_ADD: + case VK_MULTIPLY: + case VK_SUBTRACT: + case VK_SEPARATOR: + case VK_DECIMAL: + Term_no_press = TRUE; + case VK_CLEAR: + case VK_HOME: + case VK_END: + case VK_PRIOR: /* Page Up */ + case VK_NEXT: /* Page Down */ + case VK_INSERT: + case VK_DELETE: + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + numpad = !ext_key; + } + + /* Special modifiers for keypad keys */ + if (numpad) Term_keypress('K'); + + /* Encode the hexidecimal scan code */ + Term_keypress(hexsym[i/16]); + Term_keypress(hexsym[i%16]); + + /* End the macro trigger */ + Term_keypress(13); + + return 1; + } + + return 0; +} + + +#ifdef __MWERKS__ +LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam); +LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +#else /* __MWERKS__ */ +LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#endif /* __MWERKS__ */ +{ + PAINTSTRUCT ps; + HDC hdc; + term_data *td; +#if 0 + MINMAXINFO FAR *lpmmi; + RECT rc; +#endif + int i; + + + /* Acquire proper "term_data" info */ + td = (term_data *)GetWindowLong(hWnd, 0); + + /* Handle message */ + switch (uMsg) + { + case WM_NCCREATE: + { + SetWindowLong(hWnd, 0, (LONG)(my_td)); + break; + } + + case WM_CREATE: + { +#ifdef USE_MUSIC + mop.dwCallback=(DWORD)hWnd; +#endif + return 0; + } + + case WM_GETMINMAXINFO: + { + MINMAXINFO FAR *lpmmi; + RECT rc; + + lpmmi = (MINMAXINFO FAR *)lParam; + + /* this message was sent before WM_NCCREATE */ + if (!td) return 1; + + /* Minimum window size is 80x24 */ + rc.left = rc.top = 0; + rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2; + rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1; + + /* Adjust */ + AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); + + /* Save minimum size */ + lpmmi->ptMinTrackSize.x = rc.right - rc.left; + lpmmi->ptMinTrackSize.y = rc.bottom - rc.top; + + return 0; + } + + case WM_PAINT: + { + BeginPaint(hWnd, &ps); + if (td) term_data_redraw(td); + EndPaint(hWnd, &ps); + ValidateRect(hWnd, NULL); + return 0; + } + +#ifdef USE_MUSIC + case MM_MCINOTIFY: + { + if(wParam == MCI_NOTIFY_SUCCESSFUL) + { + mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); + mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop); + } + return 0; + } +#endif + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + if (process_keydown(wParam, lParam)) + return 0; + break; + } + + case WM_CHAR: + { + if (Term_no_press) Term_no_press = FALSE; + else Term_keypress(wParam); + return 0; + } + + case WM_LBUTTONDOWN: + { + mousex = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1); + mousey = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1); + mouse_down = TRUE; + oldx = mousex; + oldy = mousey; + return 0; + } + + case WM_LBUTTONUP: + { + HGLOBAL hGlobal; + LPSTR lpStr; + int j, sz; + TERM_LEN dx = abs(oldx - mousex) + 1; + TERM_LEN dy = abs(oldy - mousey) + 1; + TERM_LEN ox = (oldx > mousex) ? mousex : oldx; + TERM_LEN oy = (oldy > mousey) ? mousey : oldy; + + mouse_down = FALSE; + paint_rect = FALSE; + +#ifdef JP + sz = (dx + 3) * dy; +#else + sz = (dx + 2) * dy; +#endif + hGlobal = GlobalAlloc(GHND, sz + 1); + if (hGlobal == NULL) return 0; + lpStr = (LPSTR)GlobalLock(hGlobal); + + for (i = 0; i < dy; i++) + { +#ifdef JP + char *s; + char **scr = data[0].t.scr->c; + + C_MAKE(s, (dx + 1), char); + strncpy(s, &scr[oy + i][ox], dx); + + if (ox > 0) + { + if (iskanji(scr[oy + i][ox - 1])) s[0] = ' '; + } + + if (ox + dx < data[0].cols) + { + if (iskanji(scr[oy + i][ox + dx - 1])) s[dx - 1] = ' '; + } + + for (j = 0; j < dx; j++) + { + if (s[j] == 127) s[j] = '#'; + *lpStr++ = s[j]; + } +#else + for (j = 0; j < dx; j++) + { + *lpStr++ = data[0].t.scr->c[oy + i][ox + j]; + } +#endif + if (dy > 1) + { + *lpStr++ = '\r'; + *lpStr++ = '\n'; + } + } + + GlobalUnlock(hGlobal); + if (OpenClipboard(hWnd) == 0) + { + GlobalFree(hGlobal); + return 0; + } + EmptyClipboard(); + SetClipboardData(CF_TEXT, hGlobal); + CloseClipboard(); + + Term_redraw(); + + return 0; + } + + case WM_MOUSEMOVE: + { + if (mouse_down) + { + int dx, dy; + int cx = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1); + int cy = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1); + int ox, oy; + + if (paint_rect) + { + dx = abs(oldx - mousex) + 1; + dy = abs(oldy - mousey) + 1; + ox = (oldx > mousex) ? mousex : oldx; + oy = (oldy > mousey) ? mousey : oldy; + Term_inversed_area(hWnd, ox, oy, dx, dy); + } + else + { + paint_rect = TRUE; + } + + dx = abs(cx - mousex) + 1; + dy = abs(cy - mousey) + 1; + ox = (cx > mousex) ? mousex : cx; + oy = (cy > mousey) ? mousey : cy; + Term_inversed_area(hWnd, ox, oy, dx, dy); + + oldx = cx; + oldy = cy; + } + return 0; + } + + case WM_INITMENU: + { + setup_menus(); + return 0; + } + + case WM_CLOSE: + { + if (game_in_progress && character_generated) + { + if (!can_save) + { + plog(_("今は終了できません。", "You may not do that right now.")); + return 0; + } + + /* Hack -- Forget messages */ + msg_flag = FALSE; + + forget_lite(); + forget_view(); + clear_mon_lite(); + + /* Save the game */ +#ifdef ZANGBAND + /* do_cmd_save_game(FALSE); */ +#else /* ZANGBAND */ + /* do_cmd_save_game(); */ +#endif /* ZANGBAND */ + Term_key_push(SPECIAL_KEY_QUIT); + return 0; + } + quit(NULL); + return 0; + } + + case WM_QUERYENDSESSION: + { + if (game_in_progress && character_generated) + { + /* Hack -- Forget messages */ + msg_flag = FALSE; + + /* Mega-Hack -- Delay death */ + if (p_ptr->chp < 0) p_ptr->is_dead = FALSE; + do_cmd_write_nikki(NIKKI_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----")); + + /* Hardcode panic save */ + p_ptr->panic_save = 1; + + /* Forbid suspend */ + signals_ignore_tstp(); + + /* Indicate panic save */ + (void)strcpy(p_ptr->died_from, _("(緊急セーブ)", "(panic save)")); + + /* Panic save */ + (void)save_player(); + } + quit(NULL); + return 0; + } + + case WM_QUIT: + { + quit(NULL); + return 0; + } + + case WM_COMMAND: + { + process_menus(LOWORD(wParam)); + return 0; + } + + case WM_SIZE: + { + /* this message was sent before WM_NCCREATE */ + if (!td) return 1; + + /* it was sent from inside CreateWindowEx */ + if (!td->w) return 1; + + /* was sent from WM_SIZE */ + if (td->size_hack) return 1; + + switch (wParam) + { + case SIZE_MINIMIZED: + { + /* Hide sub-windows */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + if (data[i].visible) ShowWindow(data[i].w, SW_HIDE); + } + return 0; + } + + case SIZE_MAXIMIZED: + { + /* fall through */ + } + + case SIZE_RESTORED: + { + TERM_LEN cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid; + TERM_LEN rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt; + + /* New size */ + if ((td->cols != cols) || (td->rows != rows)) + { + /* Save the new size */ + td->cols = cols; + td->rows = rows; + + if (!IsZoomed(td->w) && !IsIconic(td->w)) + { + normsize.x = td->cols; + normsize.y = td->rows; + } + + /* Activate */ + Term_activate(&td->t); + + /* Resize the term */ + Term_resize(td->cols, td->rows); + + /* Redraw later */ + InvalidateRect(td->w, NULL, TRUE); + } + + td->size_hack = TRUE; + + /* Show sub-windows */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + if (data[i].visible) ShowWindow(data[i].w, SW_SHOW); + } + + td->size_hack = FALSE; + + return 0; + } + } + break; + } + + case WM_PALETTECHANGED: + { + /* Ignore if palette change caused by itself */ + if ((HWND)wParam == hWnd) return 0; + + /* Fall through... */ + } + + case WM_QUERYNEWPALETTE: + { + if (!paletted) return 0; + + hdc = GetDC(hWnd); + + SelectPalette(hdc, hPal, FALSE); + + i = RealizePalette(hdc); + + /* if any palette entries changed, repaint the window. */ + if (i) InvalidateRect(hWnd, NULL, TRUE); + + ReleaseDC(hWnd, hdc); + + return 0; + } + + case WM_ACTIVATE: + { + if (wParam && !HIWORD(lParam)) + { + /* Do something to sub-windows */ + for (i = 1; i < MAX_TERM_DATA; i++) + { + if (!data[i].posfix) term_window_pos(&data[i], hWnd); + } + + /* Focus on main window */ + SetFocus(hWnd); + + return 0; + } + + break; + } + + case WM_ACTIVATEAPP: + { + if (IsIconic(td->w)) break; + + for (i = 1; i < MAX_TERM_DATA; i++) + { + if(data[i].visible) + { + if (wParam == TRUE) + { + ShowWindow(data[i].w, SW_SHOW); + } + else + { + ShowWindow(data[i].w, SW_HIDE); + } + } + } + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + +#ifdef __MWERKS__ +LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam); +LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +#else /* __MWERKS__ */ +LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +#endif /* __MWERKS__ */ +{ + term_data *td; +#if 0 + MINMAXINFO FAR *lpmmi; + RECT rc; +#endif + PAINTSTRUCT ps; + HDC hdc; + int i; + + + /* Acquire proper "term_data" info */ + td = (term_data *)GetWindowLong(hWnd, 0); + + /* Process message */ + switch (uMsg) + { + case WM_NCCREATE: + { + SetWindowLong(hWnd, 0, (LONG)(my_td)); + break; + } + + case WM_CREATE: + { + return 0; + } + + case WM_GETMINMAXINFO: + { + MINMAXINFO FAR *lpmmi; + RECT rc; + + lpmmi = (MINMAXINFO FAR *)lParam; + + /* this message was sent before WM_NCCREATE */ + if (!td) return 1; + + /* Minimum window size is 80x24 */ + rc.left = rc.top = 0; + rc.right = rc.left + 20 * td->tile_wid + td->size_ow1 + td->size_ow2; + rc.bottom = rc.top + 3 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1; + + /* Adjust */ + AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle); + + /* Save minimum size */ + lpmmi->ptMinTrackSize.x = rc.right - rc.left; + lpmmi->ptMinTrackSize.y = rc.bottom - rc.top; + + return 0; + } + + case WM_SIZE: + { + TERM_LEN cols; + TERM_LEN rows; + + /* this message was sent before WM_NCCREATE */ + if (!td) return 1; + + /* it was sent from inside CreateWindowEx */ + if (!td->w) return 1; + + /* was sent from inside WM_SIZE */ + if (td->size_hack) return 1; + + td->size_hack = TRUE; + + cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid; + rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt; + + /* New size */ + if ((td->cols != cols) || (td->rows != rows)) + { + /* Save old term */ + term *old_term = Term; + + /* Save the new size */ + td->cols = cols; + td->rows = rows; + + /* Activate */ + Term_activate(&td->t); + + /* Resize the term */ + Term_resize(td->cols, td->rows); + + /* Activate */ + Term_activate(old_term); + + /* Redraw later */ + InvalidateRect(td->w, NULL, TRUE); + + /* HACK - Redraw all windows */ + p_ptr->window = 0xFFFFFFFF; + handle_stuff(); + } + + td->size_hack = FALSE; + + return 0; + } + + case WM_PAINT: + { + BeginPaint(hWnd, &ps); + if (td) term_data_redraw(td); + EndPaint(hWnd, &ps); + return 0; + } + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + if (process_keydown(wParam, lParam)) + return 0; + break; + } + + case WM_CHAR: + { + if (Term_no_press) Term_no_press = FALSE; + else Term_keypress(wParam); + return 0; + } + + case WM_PALETTECHANGED: + { + /* ignore if palette change caused by itself */ + if ((HWND)wParam == hWnd) return FALSE; + /* otherwise, fall through!!! */ + } + + case WM_QUERYNEWPALETTE: + { + if (!paletted) return 0; + hdc = GetDC(hWnd); + SelectPalette(hdc, hPal, FALSE); + i = RealizePalette(hdc); + /* if any palette entries changed, repaint the window. */ + if (i) InvalidateRect(hWnd, NULL, TRUE); + ReleaseDC(hWnd, hdc); + return 0; + } + + case WM_NCLBUTTONDOWN: + { + +#ifdef HTCLOSE + if (wParam == HTCLOSE) wParam = HTSYSMENU; +#endif /* HTCLOSE */ + + if (wParam == HTSYSMENU) + { + if (td->visible) + { + td->visible = FALSE; + ShowWindow(td->w, SW_HIDE); + } + + return 0; + } + + break; + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + +#ifdef USE_SAVER + +#define MOUSE_SENS 40 + +#ifdef __MWERKS__ +LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam); +LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +#else /* __MWERKS__ */ +LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +#endif /* __MWERKS__ */ +{ + static int iMouse = 0; + static WORD xMouse = 0; + static WORD yMouse = 0; + + int dx, dy; + + + /* Process */ + switch (uMsg) + { + case WM_NCCREATE: + { + break; + } + + case WM_SETCURSOR: + { + SetCursor(NULL); + return 0; + } + +#if 0 + case WM_ACTIVATE: + { + if (LOWORD(wParam) == WA_INACTIVE) break; + + /* else fall through */ + } +#endif + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_KEYDOWN: + { + SendMessage(hWnd, WM_CLOSE, 0, 0); + return 0; + } + + case WM_MOUSEMOVE: + { + if (iMouse) + { + dx = LOWORD(lParam) - xMouse; + dy = HIWORD(lParam) - yMouse; + + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + + if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS)) + { + SendMessage(hWnd, WM_CLOSE, 0, 0); + } + } + + /* Save last location */ + iMouse = 1; + xMouse = LOWORD(lParam); + yMouse = HIWORD(lParam); + + return 0; + } + + case WM_CLOSE: + { + DestroyWindow(hwndSaver); + hwndSaver = NULL; + return 0; + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +#endif /* USE_SAVER */ + + + + + +/*** Temporary Hooks ***/ + + +/* + * Display warning message (see "z-util.c") + */ +static void hack_plog(concptr str) +{ + /* Give a warning */ + if (str) + { +#ifdef JP + MessageBox(NULL, str, "警告!", + MB_ICONEXCLAMATION | MB_OK); +#else + MessageBox(NULL, str, "Warning", + MB_ICONEXCLAMATION | MB_OK); +#endif + + } +} + + +/* + * Display error message and quit (see "z-util.c") + */ +static void hack_quit(concptr str) +{ + /* Give a warning */ + if (str) + { +#ifdef JP + MessageBox(NULL, str, "エラー!", + MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); +#else + MessageBox(NULL, str, "Error", + MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); +#endif + + } + + /* Unregister the classes */ + UnregisterClass(AppName, hInstance); + + /* Destroy the icon */ + if (hIcon) DestroyIcon(hIcon); + + /* Exit */ + exit(0); +} + + + +/*** Various hooks ***/ + + +/* + * Display warning message (see "z-util.c") + */ +static void hook_plog(concptr str) +{ + /* Warning */ + if (str) + { +#ifdef JP + MessageBox(data[0].w, str, "警告!", + MB_ICONEXCLAMATION | MB_OK); +#else + MessageBox(data[0].w, str, "Warning", + MB_ICONEXCLAMATION | MB_OK); +#endif + + } +} + + +/* + * Display error message and quit (see "z-util.c") + */ +static void hook_quit(concptr str) +{ + int i; + + + /* Give a warning */ + if (str) + { +#ifdef JP + MessageBox(data[0].w, str, "エラー!", + MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); +#else + MessageBox(data[0].w, str, "Error", + MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); +#endif + + } + + + /* Save the preferences */ + save_prefs(); + + + /*** Could use 'Term_nuke_win()' */ + + /* Destroy all windows */ + for (i = MAX_TERM_DATA - 1; i >= 0; --i) + { + term_force_font(&data[i], NULL); + if (data[i].font_want) string_free(data[i].font_want); + if (data[i].w) DestroyWindow(data[i].w); + data[i].w = 0; + } + + /* Free the bitmap stuff */ +#ifdef USE_GRAPHICS + if (infGraph.hPalette) DeleteObject(infGraph.hPalette); + if (infGraph.hBitmap) DeleteObject(infGraph.hBitmap); + + if (infMask.hPalette) DeleteObject(infMask.hPalette); + if (infMask.hBitmap) DeleteObject(infMask.hBitmap); + +#endif /* USE_GRAPHICS */ + + /*** Free some other stuff ***/ + + DeleteObject(hbrYellow); + + /* bg */ + delete_bg(); + + if (hPal) DeleteObject(hPal); + + UnregisterClass(AppName, hInstance); + + if (hIcon) DestroyIcon(hIcon); + + exit(0); +} + + + +/*** Initialize ***/ + + +/* + * Init some stuff + */ +static void init_stuff(void) +{ + int i; + + char path[1024]; + + + /* Get program name with full path */ + GetModuleFileName(hInstance, path, 512); + + /* Save the "program name" */ + argv0 = path; + + /* Get the name of the "*.ini" file */ + strcpy(path + strlen(path) - 4, ".INI"); + + /* Save the the name of the ini-file */ + ini_file = string_make(path); + + /* Analyze the path */ + i = strlen(path); + + /* Get the path */ + for (; i > 0; i--) + { + if (path[i] == '\\') + { + /* End of path */ + break; + } + } + + /* Add "lib" to the path */ + strcpy(path + i + 1, "lib\\"); + + /* Validate the path */ + validate_dir(path, TRUE); + + /* Init the file paths */ + init_file_paths(path); + + /* Hack -- Validate the paths */ + validate_dir(ANGBAND_DIR_APEX, FALSE); + validate_dir(ANGBAND_DIR_BONE, FALSE); + + /* Allow missing 'edit' directory */ + if (!check_dir(ANGBAND_DIR_EDIT)) + { + /* Must have 'data'! */ + validate_dir(ANGBAND_DIR_DATA, TRUE); + } + else + { + /* Don't need 'data' */ + validate_dir(ANGBAND_DIR_DATA, FALSE); + } + + validate_dir(ANGBAND_DIR_FILE, TRUE); + validate_dir(ANGBAND_DIR_HELP, FALSE); + validate_dir(ANGBAND_DIR_INFO, FALSE); + validate_dir(ANGBAND_DIR_PREF, TRUE); + validate_dir(ANGBAND_DIR_SAVE, FALSE); + validate_dir(ANGBAND_DIR_USER, TRUE); + validate_dir(ANGBAND_DIR_XTRA, TRUE); + + /* Build the filename */ + path_build(path, sizeof(path), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt")); + + /* Hack -- Validate the "news.txt" file */ + validate_file(path); + + +#if 0 /* #ifndef JP */ + /* Build the "font" path */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "font"); + + /* Allocate the path */ + ANGBAND_DIR_XTRA_FONT = string_make(path); + + /* Validate the "font" directory */ + validate_dir(ANGBAND_DIR_XTRA_FONT, TRUE); + + /* Build the filename */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA_FONT, "8X13.FON"); + + /* Hack -- Validate the basic font */ + validate_file(path); +#endif + + +#ifdef USE_GRAPHICS + + /* Build the "graf" path */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "graf"); + + /* Allocate the path */ + ANGBAND_DIR_XTRA_GRAF = string_make(path); + + /* Validate the "graf" directory */ + validate_dir(ANGBAND_DIR_XTRA_GRAF, TRUE); + +#endif /* USE_GRAPHICS */ + + +#ifdef USE_SOUND + + /* Build the "sound" path */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound"); + + /* Allocate the path */ + ANGBAND_DIR_XTRA_SOUND = string_make(path); + + /* Validate the "sound" directory */ + validate_dir(ANGBAND_DIR_XTRA_SOUND, FALSE); + +#endif /* USE_SOUND */ + +#ifdef USE_MUSIC + + /* Build the "music" path */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "music"); + + /* Allocate the path */ + ANGBAND_DIR_XTRA_MUSIC = string_make(path); + + /* Validate the "music" directory */ + validate_dir(ANGBAND_DIR_XTRA_MUSIC, FALSE); + +#endif /* USE_MUSIC */ + + /* Build the "help" path */ + path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "help"); + + /* Allocate the path */ + ANGBAND_DIR_XTRA_HELP = string_make(path); + + /* Validate the "help" directory */ + /* validate_dir(ANGBAND_DIR_XTRA_HELP); */ +} + +/*! + * @brief (Windows固有)変愚蛮怒が起動済かどうかのチェック + */ +static bool is_already_running(void) +{ + bool result = FALSE; + HANDLE hMutex; + + hMutex = CreateMutex(NULL, TRUE, VERSION_NAME); + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + result = TRUE; + } + return result; +} + + +/*! + * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント + */ +int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, + LPSTR lpCmdLine, int nCmdShow) +{ + int i; + + WNDCLASS wc; + HDC hdc; + MSG msg; + + setlocale(LC_ALL, "ja_JP.utf8"); + + /* Unused */ + (void)nCmdShow; + + /* Save globally */ + hInstance = hInst; + + + /* Prevent multiple run */ + if (is_already_running()) + { + MessageBox(NULL, + _("変愚蛮怒はすでに起動しています。", "Hengband is already running."), + _("エラー!", "Error") , + MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP); + return FALSE; + } + + if (hPrevInst == NULL) + { + wc.style = CS_CLASSDC; + wc.lpfnWndProc = AngbandWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; /* one long pointer to term_data */ + wc.hInstance = hInst; + wc.hIcon = hIcon = LoadIcon(hInst, AppName); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = AppName; + wc.lpszClassName = AppName; + + if (!RegisterClass(&wc)) exit(1); + + wc.lpfnWndProc = AngbandListProc; + wc.lpszMenuName = NULL; + wc.lpszClassName = AngList; + + if (!RegisterClass(&wc)) exit(2); + +#ifdef USE_SAVER + + wc.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS; + wc.lpfnWndProc = AngbandSaverProc; + wc.hCursor = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "WindowsScreenSaverClass"; + + if (!RegisterClass(&wc)) exit(3); + +#endif + + } + + /* Temporary hooks */ + plog_aux = hack_plog; + quit_aux = hack_quit; + core_aux = hack_quit; + + /* Prepare the filepaths */ + init_stuff(); + + /* Initialize the keypress analyzer */ + for (i = 0; special_key_list[i]; ++i) + { + special_key[special_key_list[i]] = TRUE; + } + /* Initialize the keypress analyzer */ + for (i = 0; ignore_key_list[i]; ++i) + { + ignore_key[ignore_key_list[i]] = TRUE; + } + + /* Determine if display is 16/256/true color */ + hdc = GetDC(NULL); + colors16 = (GetDeviceCaps(hdc, BITSPIXEL) == 4); + paletted = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? TRUE : FALSE); + ReleaseDC(NULL, hdc); + + /* Initialize the colors */ + for (i = 0; i < 256; i++) + { + byte rv, gv, bv; + + /* Extract desired values */ + rv = angband_color_table[i][1]; + gv = angband_color_table[i][2]; + bv = angband_color_table[i][3]; + + /* Extract the "complex" code */ + win_clr[i] = PALETTERGB(rv, gv, bv); + + /* Save the "simple" code */ + angband_color_table[i][0] = win_pal[i]; + } + + /* Prepare the windows */ + init_windows(); + + /* bg */ + init_bg(); + + /* Activate hooks */ + plog_aux = hook_plog; + quit_aux = hook_quit; + core_aux = hook_quit; + + /* Set the system suffix */ + ANGBAND_SYS = "win"; + + /* Set the keyboard suffix */ + if (7 != GetKeyboardType(0)) + ANGBAND_KEYBOARD = "0"; + else + { + /* Japanese keyboard */ + switch (GetKeyboardType(1)) + { + case 0x0D01: case 0x0D02: + case 0x0D03: case 0x0D04: + case 0x0D05: case 0x0D06: + /* NEC PC-98x1 */ + ANGBAND_KEYBOARD = "NEC98"; + break; + default: + /* PC/AT */ + ANGBAND_KEYBOARD = "JAPAN"; + } + } + + /* Catch nasty signals */ + signals_init(); + + Term_activate(term_screen); + init_angband(); + + /* We are now initialized */ + initialized = TRUE; +#ifdef CHUUKEI + if(lpCmdLine[0] == '-'){ + switch(lpCmdLine[1]) + { + case 'p': + case 'P': + { + if (!lpCmdLine[2]) break; + chuukei_server = TRUE; + if(connect_chuukei_server(&lpCmdLine[2])<0){ + msg_print("connect fail"); + return 0; + } + msg_print("connect"); + msg_print(NULL); + break; + } + + case 'c': + case 'C': + { + if (!lpCmdLine[2]) break; + chuukei_client = TRUE; + connect_chuukei_server(&lpCmdLine[2]); + play_game(FALSE); + quit(NULL); + return 0; + } + case 'X': + case 'x': + { + if (!lpCmdLine[2]) break; + prepare_browse_movie(&lpCmdLine[2]); + play_game(FALSE); + quit(NULL); + return 0; + } + } + } +#endif + +#ifdef CHUUKEI + /* Did the user double click on a save file? */ + if(!chuukei_server) check_for_save_file(lpCmdLine); +#else + /* Did the user double click on a save file? */ + check_for_save_file(lpCmdLine); +#endif + + /* Prompt the user */ + prt(_("[ファイル] メニューの [新規] または [開く] を選択してください。", "[Choose 'New' or 'Open' from the 'File' menu]"), 23, _(8, 17)); + + Term_fresh(); + + /* Process messages forever */ + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + /* Paranoia */ + quit(NULL); + + /* Paranoia */ + return (0); +} + + +#endif /* WINDOWS */ + diff --git a/src/melee.h b/src/melee.h index 00052505a..43c008c10 100644 --- a/src/melee.h +++ b/src/melee.h @@ -1,6 +1,6 @@ -extern bool test_hit_norm(HIT_RELIABILITY chance, ARMOUR_CLASS ac, bool visible); -extern PERCENTAGE hit_chance(HIT_RELIABILITY chance, ARMOUR_CLASS ac); -extern HIT_POINT critical_norm(WEIGHT weight, int plus, HIT_POINT dam, s16b meichuu, BIT_FLAGS mode); -extern bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode); -extern bool make_attack_normal(MONSTER_IDX m_idx); - +extern bool test_hit_norm(HIT_RELIABILITY chance, ARMOUR_CLASS ac, bool visible); +extern PERCENTAGE hit_chance(HIT_RELIABILITY chance, ARMOUR_CLASS ac); +extern HIT_POINT critical_norm(WEIGHT weight, int plus, HIT_POINT dam, s16b meichuu, BIT_FLAGS mode); +extern bool py_attack(POSITION y, POSITION x, BIT_FLAGS mode); +extern bool make_attack_normal(MONSTER_IDX m_idx); + diff --git a/src/monster-status.h b/src/monster-status.h index 753349b91..f6a88cefb 100644 --- a/src/monster-status.h +++ b/src/monster-status.h @@ -1,5 +1,5 @@ - -extern HIT_POINT mon_damage_mod(monster_type *m_ptr, HIT_POINT dam, bool is_psy_spear); -extern bool mon_take_hit(MONSTER_IDX m_idx, HIT_POINT dam, bool *fear, concptr note); -extern int get_mproc_idx(MONSTER_IDX m_idx, int mproc_type); - + +extern HIT_POINT mon_damage_mod(monster_type *m_ptr, HIT_POINT dam, bool is_psy_spear); +extern bool mon_take_hit(MONSTER_IDX m_idx, HIT_POINT dam, bool *fear, concptr note); +extern int get_mproc_idx(MONSTER_IDX m_idx, int mproc_type); + diff --git a/src/monsterrace-hook.h b/src/monsterrace-hook.h index 18e82e98f..bdc9b3072 100644 --- a/src/monsterrace-hook.h +++ b/src/monsterrace-hook.h @@ -1,69 +1,69 @@ - -/*! -* vaultに配置可能なモンスターの条件を指定するマクロ / Monster validation macro -* -* Line 1 -- forbid town monsters -* Line 2 -- forbid uniques -* Line 3 -- forbid aquatic monsters -*/ -#define vault_monster_okay(I) \ - (mon_hook_dungeon(I) && \ - !(r_info[I].flags1 & RF1_UNIQUE) && \ - !(r_info[I].flags7 & RF7_UNIQUE2) && \ - !(r_info[I].flagsr & RFR_RES_ALL) && \ - !(r_info[I].flags7 & RF7_AQUATIC)) - -extern int vault_aux_race; -extern char vault_aux_char; -extern BIT_FLAGS vault_aux_dragon_mask4; - -extern bool mon_hook_quest(MONRACE_IDX r_idx); -extern bool mon_hook_dungeon(MONRACE_IDX r_idx); -extern bool mon_hook_ocean(MONRACE_IDX r_idx); -extern bool mon_hook_shore(MONRACE_IDX r_idx); -extern bool mon_hook_waste(MONRACE_IDX r_idx); -extern bool mon_hook_town(MONRACE_IDX r_idx); -extern bool mon_hook_wood(MONRACE_IDX r_idx); -extern bool mon_hook_volcano(MONRACE_IDX r_idx); -extern bool mon_hook_wood(MONRACE_IDX r_idx); -extern bool mon_hook_volcano(MONRACE_IDX r_idx); -extern bool mon_hook_mountain(MONRACE_IDX r_idx); -extern bool mon_hook_grass(MONRACE_IDX r_idx); -extern bool mon_hook_deep_water(MONRACE_IDX r_idx); -extern bool mon_hook_shallow_water(MONRACE_IDX r_idx); -extern bool mon_hook_lava(MONRACE_IDX r_idx); -extern bool mon_hook_floor(MONRACE_IDX r_idx); - -extern void vault_prep_clone(void); -extern void vault_prep_dragon(void); -extern void vault_prep_symbol(void); - -extern bool vault_aux_lite(MONRACE_IDX r_idx); -extern bool vault_aux_shards(MONRACE_IDX r_idx); -extern bool vault_aux_simple(MONRACE_IDX r_idx); -extern bool vault_aux_jelly(MONRACE_IDX r_idx); -extern bool vault_aux_animal(MONRACE_IDX r_idx); -extern bool vault_aux_undead(MONRACE_IDX r_idx); -extern bool vault_aux_chapel_g(MONRACE_IDX r_idx); -extern bool vault_aux_kennel(MONRACE_IDX r_idx); -extern bool vault_aux_mimic(MONRACE_IDX r_idx); -extern bool vault_aux_clone(MONRACE_IDX r_idx); -extern bool vault_aux_symbol_e(MONRACE_IDX r_idx); -extern bool vault_aux_symbol_g(MONRACE_IDX r_idx); -extern bool vault_aux_orc(MONRACE_IDX r_idx); -extern bool vault_aux_troll(MONRACE_IDX r_idx); -extern bool vault_aux_giant(MONRACE_IDX r_idx); -extern bool vault_aux_dragon(MONRACE_IDX r_idx); -extern bool vault_aux_demon(MONRACE_IDX r_idx); -extern bool vault_aux_cthulhu(MONRACE_IDX r_idx); -extern bool vault_aux_dark_elf(MONRACE_IDX r_idx); - -extern bool monster_living(MONRACE_IDX r_idx); -extern bool no_questor_or_bounty_uniques(MONRACE_IDX r_idx); -extern bool monster_hook_human(MONRACE_IDX r_idx); -extern bool get_nightmare(MONRACE_IDX r_idx); -extern bool monster_is_fishing_target(MONRACE_IDX r_idx); -extern bool monster_can_entry_arena(MONRACE_IDX r_idx); - - - + +/*! +* vaultに配置可能なモンスターの条件を指定するマクロ / Monster validation macro +* +* Line 1 -- forbid town monsters +* Line 2 -- forbid uniques +* Line 3 -- forbid aquatic monsters +*/ +#define vault_monster_okay(I) \ + (mon_hook_dungeon(I) && \ + !(r_info[I].flags1 & RF1_UNIQUE) && \ + !(r_info[I].flags7 & RF7_UNIQUE2) && \ + !(r_info[I].flagsr & RFR_RES_ALL) && \ + !(r_info[I].flags7 & RF7_AQUATIC)) + +extern int vault_aux_race; +extern char vault_aux_char; +extern BIT_FLAGS vault_aux_dragon_mask4; + +extern bool mon_hook_quest(MONRACE_IDX r_idx); +extern bool mon_hook_dungeon(MONRACE_IDX r_idx); +extern bool mon_hook_ocean(MONRACE_IDX r_idx); +extern bool mon_hook_shore(MONRACE_IDX r_idx); +extern bool mon_hook_waste(MONRACE_IDX r_idx); +extern bool mon_hook_town(MONRACE_IDX r_idx); +extern bool mon_hook_wood(MONRACE_IDX r_idx); +extern bool mon_hook_volcano(MONRACE_IDX r_idx); +extern bool mon_hook_wood(MONRACE_IDX r_idx); +extern bool mon_hook_volcano(MONRACE_IDX r_idx); +extern bool mon_hook_mountain(MONRACE_IDX r_idx); +extern bool mon_hook_grass(MONRACE_IDX r_idx); +extern bool mon_hook_deep_water(MONRACE_IDX r_idx); +extern bool mon_hook_shallow_water(MONRACE_IDX r_idx); +extern bool mon_hook_lava(MONRACE_IDX r_idx); +extern bool mon_hook_floor(MONRACE_IDX r_idx); + +extern void vault_prep_clone(void); +extern void vault_prep_dragon(void); +extern void vault_prep_symbol(void); + +extern bool vault_aux_lite(MONRACE_IDX r_idx); +extern bool vault_aux_shards(MONRACE_IDX r_idx); +extern bool vault_aux_simple(MONRACE_IDX r_idx); +extern bool vault_aux_jelly(MONRACE_IDX r_idx); +extern bool vault_aux_animal(MONRACE_IDX r_idx); +extern bool vault_aux_undead(MONRACE_IDX r_idx); +extern bool vault_aux_chapel_g(MONRACE_IDX r_idx); +extern bool vault_aux_kennel(MONRACE_IDX r_idx); +extern bool vault_aux_mimic(MONRACE_IDX r_idx); +extern bool vault_aux_clone(MONRACE_IDX r_idx); +extern bool vault_aux_symbol_e(MONRACE_IDX r_idx); +extern bool vault_aux_symbol_g(MONRACE_IDX r_idx); +extern bool vault_aux_orc(MONRACE_IDX r_idx); +extern bool vault_aux_troll(MONRACE_IDX r_idx); +extern bool vault_aux_giant(MONRACE_IDX r_idx); +extern bool vault_aux_dragon(MONRACE_IDX r_idx); +extern bool vault_aux_demon(MONRACE_IDX r_idx); +extern bool vault_aux_cthulhu(MONRACE_IDX r_idx); +extern bool vault_aux_dark_elf(MONRACE_IDX r_idx); + +extern bool monster_living(MONRACE_IDX r_idx); +extern bool no_questor_or_bounty_uniques(MONRACE_IDX r_idx); +extern bool monster_hook_human(MONRACE_IDX r_idx); +extern bool get_nightmare(MONRACE_IDX r_idx); +extern bool monster_is_fishing_target(MONRACE_IDX r_idx); +extern bool monster_can_entry_arena(MONRACE_IDX r_idx); + + + diff --git a/src/object-curse.c b/src/object-curse.c index 9b426efd1..9e28459c2 100644 --- a/src/object-curse.c +++ b/src/object-curse.c @@ -1,103 +1,103 @@ -#include "angband.h" - -/*! - * @brief アイテムに付加される可能性のある呪いを指定する。 - * @param power 呪いの段階 - * @param o_ptr 呪いをかけられる装備オブジェクトの構造体参照ポインタ - * @return 与える呪いのID - */ -BIT_FLAGS get_curse(int power, object_type *o_ptr) -{ - BIT_FLAGS new_curse; - - while(1) - { - new_curse = (1 << (randint0(MAX_CURSE)+4)); - if (power == 2) - { - if (!(new_curse & TRC_HEAVY_MASK)) continue; - } - else if (power == 1) - { - if (new_curse & TRC_SPECIAL_MASK) continue; - } - else if (power == 0) - { - if (new_curse & TRC_HEAVY_MASK) continue; - } - if (new_curse == TRC_LOW_MELEE && !object_is_weapon(o_ptr)) continue; - if (new_curse == TRC_LOW_AC && !object_is_armour(o_ptr)) continue; - break; - } - return new_curse; -} - -/*! - * @brief 装備への呪い付加判定と付加処理 - * @param chance 呪いの基本確率 - * @param heavy_chance さらに重い呪いとなる確率 - * @return なし - */ -void curse_equipment(PERCENTAGE chance, PERCENTAGE heavy_chance) -{ - bool changed = FALSE; - int curse_power = 0; - BIT_FLAGS new_curse; - BIT_FLAGS oflgs[TR_FLAG_SIZE]; - object_type *o_ptr = &inventory[INVEN_RARM + randint0(12)]; - GAME_TEXT o_name[MAX_NLEN]; - - if (randint1(100) > chance) return; - - if (!o_ptr->k_idx) return; - - object_flags(o_ptr, oflgs); - - object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); - - /* Extra, biased saving throw for blessed items */ - if (have_flag(oflgs, TR_BLESSED)) - { -#ifdef JP - msg_format("祝福された%sは呪いを跳ね返した!", o_name, -#else - msg_format("Your blessed %s resist%s cursing!", o_name, -#endif - - ((o_ptr->number > 1) ? "" : "s")); - /* Hmmm -- can we wear multiple items? If not, this is unnecessary */ - return; - } - - if ((randint1(100) <= heavy_chance) && - (object_is_artifact(o_ptr) || object_is_ego(o_ptr))) - { - if (!(o_ptr->curse_flags & TRC_HEAVY_CURSE)) - changed = TRUE; - o_ptr->curse_flags |= TRC_HEAVY_CURSE; - o_ptr->curse_flags |= TRC_CURSED; - curse_power++; - } - else - { - if (!object_is_cursed(o_ptr)) - changed = TRUE; - o_ptr->curse_flags |= TRC_CURSED; - } - if (heavy_chance >= 50) curse_power++; - - new_curse = get_curse(curse_power, o_ptr); - if (!(o_ptr->curse_flags & new_curse)) - { - changed = TRUE; - o_ptr->curse_flags |= new_curse; - } - - if (changed) - { - msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding %s..."), o_name); - o_ptr->feeling = FEEL_NONE; - } - p_ptr->update |= (PU_BONUS); -} - +#include "angband.h" + +/*! + * @brief アイテムに付加される可能性のある呪いを指定する。 + * @param power 呪いの段階 + * @param o_ptr 呪いをかけられる装備オブジェクトの構造体参照ポインタ + * @return 与える呪いのID + */ +BIT_FLAGS get_curse(int power, object_type *o_ptr) +{ + BIT_FLAGS new_curse; + + while(1) + { + new_curse = (1 << (randint0(MAX_CURSE)+4)); + if (power == 2) + { + if (!(new_curse & TRC_HEAVY_MASK)) continue; + } + else if (power == 1) + { + if (new_curse & TRC_SPECIAL_MASK) continue; + } + else if (power == 0) + { + if (new_curse & TRC_HEAVY_MASK) continue; + } + if (new_curse == TRC_LOW_MELEE && !object_is_weapon(o_ptr)) continue; + if (new_curse == TRC_LOW_AC && !object_is_armour(o_ptr)) continue; + break; + } + return new_curse; +} + +/*! + * @brief 装備への呪い付加判定と付加処理 + * @param chance 呪いの基本確率 + * @param heavy_chance さらに重い呪いとなる確率 + * @return なし + */ +void curse_equipment(PERCENTAGE chance, PERCENTAGE heavy_chance) +{ + bool changed = FALSE; + int curse_power = 0; + BIT_FLAGS new_curse; + BIT_FLAGS oflgs[TR_FLAG_SIZE]; + object_type *o_ptr = &inventory[INVEN_RARM + randint0(12)]; + GAME_TEXT o_name[MAX_NLEN]; + + if (randint1(100) > chance) return; + + if (!o_ptr->k_idx) return; + + object_flags(o_ptr, oflgs); + + object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); + + /* Extra, biased saving throw for blessed items */ + if (have_flag(oflgs, TR_BLESSED)) + { +#ifdef JP + msg_format("祝福された%sは呪いを跳ね返した!", o_name, +#else + msg_format("Your blessed %s resist%s cursing!", o_name, +#endif + + ((o_ptr->number > 1) ? "" : "s")); + /* Hmmm -- can we wear multiple items? If not, this is unnecessary */ + return; + } + + if ((randint1(100) <= heavy_chance) && + (object_is_artifact(o_ptr) || object_is_ego(o_ptr))) + { + if (!(o_ptr->curse_flags & TRC_HEAVY_CURSE)) + changed = TRUE; + o_ptr->curse_flags |= TRC_HEAVY_CURSE; + o_ptr->curse_flags |= TRC_CURSED; + curse_power++; + } + else + { + if (!object_is_cursed(o_ptr)) + changed = TRUE; + o_ptr->curse_flags |= TRC_CURSED; + } + if (heavy_chance >= 50) curse_power++; + + new_curse = get_curse(curse_power, o_ptr); + if (!(o_ptr->curse_flags & new_curse)) + { + changed = TRUE; + o_ptr->curse_flags |= new_curse; + } + + if (changed) + { + msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding %s..."), o_name); + o_ptr->feeling = FEEL_NONE; + } + p_ptr->update |= (PU_BONUS); +} + diff --git a/src/object-curse.h b/src/object-curse.h index 60ade11ec..fb2b0b237 100644 --- a/src/object-curse.h +++ b/src/object-curse.h @@ -1,2 +1,2 @@ -extern BIT_FLAGS get_curse(int power, object_type *o_ptr); -extern void curse_equipment(PERCENTAGE chance, PERCENTAGE heavy_chance); +extern BIT_FLAGS get_curse(int power, object_type *o_ptr); +extern void curse_equipment(PERCENTAGE chance, PERCENTAGE heavy_chance); diff --git a/src/object-hook.h b/src/object-hook.h index ca77f8784..b67ef3910 100644 --- a/src/object-hook.h +++ b/src/object-hook.h @@ -1,28 +1,28 @@ - -extern bool item_tester_hook_convertible(object_type *o_ptr); -extern bool item_tester_hook_recharge(object_type *o_ptr); -extern bool item_tester_hook_orthodox_melee_weapons(object_type *o_ptr); -extern bool item_tester_hook_melee_weapon(object_type *o_ptr); -extern bool item_tester_hook_ammo(object_type *o_ptr); -extern bool item_tester_hook_broken_weapon(object_type *o_ptr); -extern bool item_tester_hook_boomerang(object_type *o_ptr); -extern bool item_tester_hook_eatable(object_type *o_ptr); -extern bool item_tester_hook_mochikae(object_type *o_ptr); -extern bool item_tester_hook_activate(object_type *o_ptr); -extern bool item_tester_hook_wear(object_type *o_ptr); -extern bool item_tester_hook_use(object_type *o_ptr); -extern bool item_tester_hook_quaff(object_type *o_ptr); -extern bool item_tester_hook_readable(object_type *o_ptr); -extern bool item_tester_hook_melee_ammo(object_type *o_ptr); -extern bool item_tester_hook_weapon_except_bow(object_type *o_ptr); -extern bool item_tester_hook_cursed(object_type *o_ptr); -extern bool item_tester_hook_nameless_weapon_armour(object_type *o_ptr); -extern bool item_tester_hook_identify(object_type *o_ptr); -extern bool item_tester_hook_identify_weapon_armour(object_type *o_ptr); -extern bool item_tester_hook_identify_fully(object_type *o_ptr); -extern bool item_tester_hook_identify_fully_weapon_armour(object_type *o_ptr); -extern bool item_tester_hook_recharge(object_type *o_ptr); - -extern bool item_tester_learn_spell(object_type *o_ptr); -extern bool item_tester_high_level_book(object_type *o_ptr); -extern bool item_tester_refill_lantern(object_type *o_ptr); + +extern bool item_tester_hook_convertible(object_type *o_ptr); +extern bool item_tester_hook_recharge(object_type *o_ptr); +extern bool item_tester_hook_orthodox_melee_weapons(object_type *o_ptr); +extern bool item_tester_hook_melee_weapon(object_type *o_ptr); +extern bool item_tester_hook_ammo(object_type *o_ptr); +extern bool item_tester_hook_broken_weapon(object_type *o_ptr); +extern bool item_tester_hook_boomerang(object_type *o_ptr); +extern bool item_tester_hook_eatable(object_type *o_ptr); +extern bool item_tester_hook_mochikae(object_type *o_ptr); +extern bool item_tester_hook_activate(object_type *o_ptr); +extern bool item_tester_hook_wear(object_type *o_ptr); +extern bool item_tester_hook_use(object_type *o_ptr); +extern bool item_tester_hook_quaff(object_type *o_ptr); +extern bool item_tester_hook_readable(object_type *o_ptr); +extern bool item_tester_hook_melee_ammo(object_type *o_ptr); +extern bool item_tester_hook_weapon_except_bow(object_type *o_ptr); +extern bool item_tester_hook_cursed(object_type *o_ptr); +extern bool item_tester_hook_nameless_weapon_armour(object_type *o_ptr); +extern bool item_tester_hook_identify(object_type *o_ptr); +extern bool item_tester_hook_identify_weapon_armour(object_type *o_ptr); +extern bool item_tester_hook_identify_fully(object_type *o_ptr); +extern bool item_tester_hook_identify_fully_weapon_armour(object_type *o_ptr); +extern bool item_tester_hook_recharge(object_type *o_ptr); + +extern bool item_tester_learn_spell(object_type *o_ptr); +extern bool item_tester_high_level_book(object_type *o_ptr); +extern bool item_tester_refill_lantern(object_type *o_ptr); diff --git a/src/objectkind-hook.h b/src/objectkind-hook.h index 15496a75d..351e2b7c2 100644 --- a/src/objectkind-hook.h +++ b/src/objectkind-hook.h @@ -1,12 +1,12 @@ - -bool kind_is_cloak(KIND_OBJECT_IDX k_idx); -bool kind_is_polearm(KIND_OBJECT_IDX k_idx); -bool kind_is_sword(KIND_OBJECT_IDX k_idx); -bool kind_is_book(KIND_OBJECT_IDX k_idx); -bool kind_is_good_book(KIND_OBJECT_IDX k_idx); -bool kind_is_armor(KIND_OBJECT_IDX k_idx); -bool kind_is_hafted(KIND_OBJECT_IDX k_idx); -bool kind_is_potion(KIND_OBJECT_IDX k_idx); - - - + +bool kind_is_cloak(KIND_OBJECT_IDX k_idx); +bool kind_is_polearm(KIND_OBJECT_IDX k_idx); +bool kind_is_sword(KIND_OBJECT_IDX k_idx); +bool kind_is_book(KIND_OBJECT_IDX k_idx); +bool kind_is_good_book(KIND_OBJECT_IDX k_idx); +bool kind_is_armor(KIND_OBJECT_IDX k_idx); +bool kind_is_hafted(KIND_OBJECT_IDX k_idx); +bool kind_is_potion(KIND_OBJECT_IDX k_idx); + + + diff --git a/src/player-damage.h b/src/player-damage.h index a045f3359..67c59dbee 100644 --- a/src/player-damage.h +++ b/src/player-damage.h @@ -1,14 +1,14 @@ - -extern bool hates_acid(object_type *o_ptr); -extern bool hates_elec(object_type *o_ptr); -extern bool hates_fire(object_type *o_ptr); -extern bool hates_cold(object_type *o_ptr); -extern int set_acid_destroy(object_type *o_ptr); -extern int set_elec_destroy(object_type *o_ptr); -extern int set_fire_destroy(object_type *o_ptr); -extern int set_cold_destroy(object_type *o_ptr); -extern int inven_damage(inven_func typ, int perc); -extern HIT_POINT acid_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); -extern HIT_POINT elec_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); -extern HIT_POINT fire_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); -extern HIT_POINT cold_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); + +extern bool hates_acid(object_type *o_ptr); +extern bool hates_elec(object_type *o_ptr); +extern bool hates_fire(object_type *o_ptr); +extern bool hates_cold(object_type *o_ptr); +extern int set_acid_destroy(object_type *o_ptr); +extern int set_elec_destroy(object_type *o_ptr); +extern int set_fire_destroy(object_type *o_ptr); +extern int set_cold_destroy(object_type *o_ptr); +extern int inven_damage(inven_func typ, int perc); +extern HIT_POINT acid_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); +extern HIT_POINT elec_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); +extern HIT_POINT fire_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); +extern HIT_POINT cold_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura); diff --git a/src/realm-arcane.h b/src/realm-arcane.h index 5307bc33d..734d9090d 100644 --- a/src/realm-arcane.h +++ b/src/realm-arcane.h @@ -1 +1 @@ -extern concptr do_arcane_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_arcane_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-chaos.h b/src/realm-chaos.h index 458d4701b..050210b93 100644 --- a/src/realm-chaos.h +++ b/src/realm-chaos.h @@ -1 +1 @@ -extern concptr do_chaos_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_chaos_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-craft.h b/src/realm-craft.h index 7ea6dff75..83a6e22bc 100644 --- a/src/realm-craft.h +++ b/src/realm-craft.h @@ -1 +1 @@ -concptr do_craft_spell(SPELL_IDX spell, BIT_FLAGS mode); +concptr do_craft_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-crusade.h b/src/realm-crusade.h index ab8f9fbae..b8204b15d 100644 --- a/src/realm-crusade.h +++ b/src/realm-crusade.h @@ -1 +1 @@ -extern concptr do_crusade_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_crusade_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-daemon.h b/src/realm-daemon.h index 2dcdb1cf3..5e1e1ed4e 100644 --- a/src/realm-daemon.h +++ b/src/realm-daemon.h @@ -1,2 +1,2 @@ -extern concptr do_daemon_spell(SPELL_IDX spell, BIT_FLAGS mode); - +extern concptr do_daemon_spell(SPELL_IDX spell, BIT_FLAGS mode); + diff --git a/src/realm-death.h b/src/realm-death.h index 9a2a0a974..b7fee631c 100644 --- a/src/realm-death.h +++ b/src/realm-death.h @@ -1 +1 @@ -extern concptr do_death_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_death_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-hex.h b/src/realm-hex.h index d42a7d0a1..f688f75ef 100644 --- a/src/realm-hex.h +++ b/src/realm-hex.h @@ -1,14 +1,14 @@ -/*! - * @file realm-hex.h - */ - -extern bool stop_hex_spell_all(void); -extern bool stop_hex_spell(void); -extern void check_hex(void); -extern bool hex_spell_fully(void); -extern void revenge_spell(void); -extern void revenge_store(HIT_POINT dam); -extern bool teleport_barrier(MONSTER_IDX m_idx); -extern bool magic_barrier(MONSTER_IDX m_idx); -extern bool multiply_barrier(MONSTER_IDX m_idx); -extern concptr do_hex_spell(SPELL_IDX spell, BIT_FLAGS mode); +/*! + * @file realm-hex.h + */ + +extern bool stop_hex_spell_all(void); +extern bool stop_hex_spell(void); +extern void check_hex(void); +extern bool hex_spell_fully(void); +extern void revenge_spell(void); +extern void revenge_store(HIT_POINT dam); +extern bool teleport_barrier(MONSTER_IDX m_idx); +extern bool magic_barrier(MONSTER_IDX m_idx); +extern bool multiply_barrier(MONSTER_IDX m_idx); +extern concptr do_hex_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-hissatsu.h b/src/realm-hissatsu.h index c197e9bda..f7e9f4e68 100644 --- a/src/realm-hissatsu.h +++ b/src/realm-hissatsu.h @@ -1 +1 @@ -extern concptr do_hissatsu_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_hissatsu_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-life.h b/src/realm-life.h index c76b6d91a..fe0607f6f 100644 --- a/src/realm-life.h +++ b/src/realm-life.h @@ -1 +1 @@ -extern concptr do_life_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_life_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-nature.c b/src/realm-nature.c index a2195f932..460a80363 100644 --- a/src/realm-nature.c +++ b/src/realm-nature.c @@ -1,567 +1,567 @@ -#include "angband.h" -#include "cmd-spell.h" -#include "projection.h" -#include "spells-summon.h" -#include "spells-status.h" -#include "avatar.h" - - -/*! -* @brief 自然領域魔法の各処理を行う -* @param spell 魔法ID -* @param mode 処理内容 (SPELL_NAME / SPELL_DESC / SPELL_INFO / SPELL_CAST) -* @return SPELL_NAME / SPELL_DESC / SPELL_INFO 時には文字列ポインタを返す。SPELL_CAST時はNULL文字列を返す。 -*/ -concptr do_nature_spell(SPELL_IDX spell, BIT_FLAGS mode) -{ - bool name = (mode == SPELL_NAME) ? TRUE : FALSE; - bool desc = (mode == SPELL_DESC) ? TRUE : FALSE; - bool info = (mode == SPELL_INFO) ? TRUE : FALSE; - bool cast = (mode == SPELL_CAST) ? TRUE : FALSE; - - DIRECTION dir; - PLAYER_LEVEL plev = p_ptr->lev; - - switch (spell) - { - case 0: - if (name) return _("モンスター感知", "Detect Creatures"); - if (desc) return _("近くの全ての見えるモンスターを感知する。", "Detects all monsters in your vicinity unless invisible."); - - { - POSITION rad = DETECT_RAD_DEFAULT; - - if (info) return info_radius(rad); - - if (cast) - { - detect_monsters_normal(rad); - } - } - break; - - case 1: - if (name) return _("稲妻", "Lightning"); - if (desc) return _("電撃の短いビームを放つ。", "Fires a short beam of lightning."); - - { - DICE_NUMBER dice = 3 + (plev - 1) / 5; - DICE_SID sides = 4; - POSITION range = plev / 6 + 2; - - if (info) return format("%s%dd%d %s%d", KWD_DAM, dice, sides, KWD_RANGE, range); - - if (cast) - { - project_length = range; - - if (!get_aim_dir(&dir)) return NULL; - - fire_beam(GF_ELEC, dir, damroll(dice, sides)); - } - } - break; - - case 2: - if (name) return _("罠と扉感知", "Detect Doors and Traps"); - if (desc) return _("近くの全ての罠と扉を感知する。", "Detects traps, doors, and stairs in your vicinity."); - - { - POSITION rad = DETECT_RAD_DEFAULT; - - if (info) return info_radius(rad); - - if (cast) - { - detect_traps(rad, TRUE); - detect_doors(rad); - detect_stairs(rad); - } - } - break; - - case 3: - if (name) return _("食糧生成", "Produce Food"); - if (desc) return _("食料を一つ作り出す。", "Produces a Ration of Food."); - - { - if (cast) - { - object_type forge, *q_ptr = &forge; - msg_print(_("食料を生成した。", "A food ration is produced.")); - - /* Create the food ration */ - object_prep(q_ptr, lookup_kind(TV_FOOD, SV_FOOD_RATION)); - - /* Drop the object from heaven */ - (void)drop_near(q_ptr, -1, p_ptr->y, p_ptr->x); - } - } - break; - - case 4: - if (name) return _("日の光", "Daylight"); - if (desc) return _("光源が照らしている範囲か部屋全体を永久に明るくする。", "Lights up nearby area and the inside of a room permanently."); - - { - DICE_NUMBER dice = 2; - DICE_SID sides = plev / 2; - POSITION rad = (plev / 10) + 1; - - if (info) return info_damage(dice, sides, 0); - - if (cast) - { - lite_area(damroll(dice, sides), rad); - - if ((prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) && !p_ptr->resist_lite) - { - msg_print(_("日の光があなたの肉体を焦がした!", "The daylight scorches your flesh!")); - take_hit(DAMAGE_NOESCAPE, damroll(2, 2), _("日の光", "daylight"), -1); - } - } - } - break; - - case 5: - if (name) return _("動物習し", "Animal Taming"); - if (desc) return _("動物1体を魅了する。抵抗されると無効。", "Attempts to charm an animal."); - - { - int power = plev; - - if (info) return info_power(power); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - - charm_animal(dir, plev); - } - } - break; - - case 6: - if (name) return _("環境への耐性", "Resist Environment"); - if (desc) return _("一定時間、冷気、炎、電撃に対する耐性を得る。装備による耐性に累積する。", - "Gives resistance to fire, cold and electricity for a while. These resistances can be added to which from equipment for more powerful resistances."); - - { - int base = 20; - - if (info) return info_duration(base, base); - - if (cast) - { - set_oppose_cold(randint1(base) + base, FALSE); - set_oppose_fire(randint1(base) + base, FALSE); - set_oppose_elec(randint1(base) + base, FALSE); - } - } - break; - - case 7: - if (name) return _("傷と毒治療", "Cure Wounds & Poison"); - if (desc) return _("怪我を全快させ、毒を体から完全に取り除き、体力を少し回復させる。", "Heals all cut and poison status. Heals HP a little."); - - { - DICE_NUMBER dice = 2; - DICE_SID sides = 8; - - if (info) return info_heal(dice, sides, 0); - - if (cast) - { - hp_player(damroll(dice, sides)); - set_cut(0); - set_poisoned(0); - } - } - break; - - case 8: - if (name) return _("岩石溶解", "Stone to Mud"); - if (desc) return _("壁を溶かして床にする。", "Turns one rock square to mud."); - - { - DICE_NUMBER dice = 1; - DICE_SID sides = 30; - int base = 20; - - if (info) return info_damage(dice, sides, base); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - - wall_to_mud(dir, 20 + randint1(30)); - } - } - break; - - case 9: - if (name) return _("アイス・ボルト", "Frost Bolt"); - if (desc) return _("冷気のボルトもしくはビームを放つ。", "Fires a bolt or beam of cold."); - - { - DICE_NUMBER dice = 3 + (plev - 5) / 4; - DICE_SID sides = 8; - - if (info) return info_damage(dice, sides, 0); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - fire_bolt_or_beam(beam_chance() - 10, GF_COLD, dir, damroll(dice, sides)); - } - } - break; - - case 10: - if (name) return _("自然の覚醒", "Nature Awareness"); - if (desc) return _("周辺の地形を感知し、近くの罠、扉、階段、全てのモンスターを感知する。", - "Maps nearby area. Detects all monsters, traps, doors and stairs."); - - { - int rad1 = DETECT_RAD_MAP; - int rad2 = DETECT_RAD_DEFAULT; - - if (info) return info_radius(MAX(rad1, rad2)); - - if (cast) - { - map_area(rad1); - detect_traps(rad2, TRUE); - detect_doors(rad2); - detect_stairs(rad2); - detect_monsters_normal(rad2); - } - } - break; - - case 11: - if (name) return _("ファイア・ボルト", "Fire Bolt"); - if (desc) return _("火炎のボルトもしくはビームを放つ。", "Fires a bolt or beam of fire."); - - { - DICE_NUMBER dice = 5 + (plev - 5) / 4; - DICE_SID sides = 8; - - if (info) return info_damage(dice, sides, 0); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - fire_bolt_or_beam(beam_chance() - 10, GF_FIRE, dir, damroll(dice, sides)); - } - } - break; - - case 12: - if (name) return _("太陽光線", "Ray of Sunlight"); - if (desc) return _("光線を放つ。光りを嫌うモンスターに効果がある。", "Fires a beam of light which damages to light-sensitive monsters."); - - { - DICE_NUMBER dice = 6; - DICE_SID sides = 8; - - if (info) return info_damage(dice, sides, 0); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - msg_print(_("太陽光線が現れた。", "A line of sunlight appears.")); - lite_line(dir, damroll(6, 8)); - } - } - break; - - case 13: - if (name) return _("足かせ", "Entangle"); - if (desc) return _("視界内の全てのモンスターを減速させる。抵抗されると無効。", "Attempts to slow all monsters in sight."); - { - int power = plev; - if (info) return info_power(power); - if (cast) slow_monsters(plev); - } - break; - - case 14: - if (name) return _("動物召喚", "Summon Animal"); - if (desc) return _("動物を1体召喚する。", "Summons an animal."); - - { - if (cast) - { - if (!(summon_specific(-1, p_ptr->y, p_ptr->x, plev, SUMMON_ANIMAL_RANGER, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0'))) - { - msg_print(_("動物は現れなかった。", "No animals arrive.")); - } - break; - } - } - break; - - case 15: - if (name) return _("薬草治療", "Herbal Healing"); - if (desc) return _("体力を大幅に回復させ、負傷、朦朧状態、毒から全快する。", "Heals HP greatly. And heals cut, stun and poison completely."); - { - int heal = 500; - if (info) return info_heal(0, 0, heal); - if (cast) (void)cure_critical_wounds(heal); - } - break; - - case 16: - if (name) return _("階段生成", "Stair Building"); - if (desc) return _("自分のいる位置に階段を作る。", "Creates a stair which goes down or up."); - - { - if (cast) - { - stair_creation(); - } - } - break; - - case 17: - if (name) return _("肌石化", "Stone Skin"); - if (desc) return _("一定時間、ACを上昇させる。", "Gives bonus to AC for a while."); - - { - int base = 20; - DICE_SID sides = 30; - - if (info) return info_duration(base, sides); - - if (cast) - { - set_shield(randint1(sides) + base, FALSE); - } - } - break; - - case 18: - if (name) return _("真・耐性", "Resistance True"); - if (desc) return _("一定時間、酸、電撃、炎、冷気、毒に対する耐性を得る。装備による耐性に累積する。", - "Gives resistance to fire, cold, electricity, acid and poison for a while. These resistances can be added to which from equipment for more powerful resistances."); - - { - int base = 20; - - if (info) return info_duration(base, base); - - if (cast) - { - set_oppose_acid(randint1(base) + base, FALSE); - set_oppose_elec(randint1(base) + base, FALSE); - set_oppose_fire(randint1(base) + base, FALSE); - set_oppose_cold(randint1(base) + base, FALSE); - set_oppose_pois(randint1(base) + base, FALSE); - } - } - break; - - case 19: - if (name) return _("森林創造", "Forest Creation"); - if (desc) return _("周囲に木を作り出す。", "Creates trees in all adjacent squares."); - - { - if (cast) - { - tree_creation(); - } - } - break; - - case 20: - if (name) return _("動物友和", "Animal Friendship"); - if (desc) return _("視界内の全ての動物を魅了する。抵抗されると無効。", "Attempts to charm all animals in sight."); - - { - int power = plev * 2; - if (info) return info_power(power); - if (cast) charm_animals(power); - } - break; - - case 21: - if (name) return _("試金石", "Stone Tell"); - if (desc) return _("アイテムの持つ能力を完全に知る。", "*Identifies* an item."); - - { - if (cast) - { - if (!identify_fully(FALSE)) return NULL; - } - } - break; - - case 22: - if (name) return _("石の壁", "Wall of Stone"); - if (desc) return _("自分の周囲に花崗岩の壁を作る。", "Creates granite walls in all adjacent squares."); - - { - if (cast) - { - wall_stone(); - } - } - break; - - case 23: - if (name) return _("腐食防止", "Protect from Corrosion"); - if (desc) return _("アイテムを酸で傷つかないよう加工する。", "Makes an equipment acid-proof."); - - { - if (cast) - { - if (!rustproof()) return NULL; - } - } - break; - - case 24: - if (name) return _("地震", "Earthquake"); - if (desc) return _("周囲のダンジョンを揺らし、壁と床をランダムに入れ変える。", - "Shakes dungeon structure, and results in random swapping of floors and walls."); - - { - POSITION rad = 10; - - if (info) return info_radius(rad); - - if (cast) - { - earthquake(p_ptr->y, p_ptr->x, rad); - } - } - break; - - case 25: - if (name) return _("カマイタチ", "Whirlwind"); - if (desc) return _("全方向に向かって攻撃する。", "Attacks all adjacent monsters."); - if (cast) massacre(); - break; - - case 26: - if (name) return _("ブリザード", "Blizzard"); - if (desc) return _("巨大な冷気の球を放つ。", "Fires a huge ball of cold."); - - { - HIT_POINT dam = 70 + plev * 3 / 2; - POSITION rad = plev / 12 + 1; - - if (info) return info_damage(0, 0, dam); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - - fire_ball(GF_COLD, dir, dam, rad); - } - } - break; - - case 27: - if (name) return _("稲妻嵐", "Lightning Storm"); - if (desc) return _("巨大な電撃の球を放つ。", "Fires a huge electric ball."); - - { - HIT_POINT dam = 90 + plev * 3 / 2; - POSITION rad = plev / 12 + 1; - - if (info) return info_damage(0, 0, dam); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - fire_ball(GF_ELEC, dir, dam, rad); - break; - } - } - break; - - case 28: - if (name) return _("渦潮", "Whirlpool"); - if (desc) return _("巨大な水の球を放つ。", "Fires a huge ball of water."); - - { - HIT_POINT dam = 100 + plev * 3 / 2; - POSITION rad = plev / 12 + 1; - - if (info) return info_damage(0, 0, dam); - - if (cast) - { - if (!get_aim_dir(&dir)) return NULL; - fire_ball(GF_WATER, dir, dam, rad); - } - } - break; - - case 29: - if (name) return _("陽光召喚", "Call Sunlight"); - if (desc) return _("自分を中心とした光の球を発生させる。さらに、その階全体を永久に照らし、ダンジョン内すべてのアイテムを感知する。", - "Generates ball of light centered on you. Maps and lights whole dungeon level. Knows all objects location."); - - { - HIT_POINT dam = 150; - POSITION rad = 8; - - if (info) return info_damage(0, 0, dam / 2); - - if (cast) - { - fire_ball(GF_LITE, 0, dam, rad); - chg_virtue(V_KNOWLEDGE, 1); - chg_virtue(V_ENLIGHTEN, 1); - wiz_lite(FALSE); - - if ((prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) && !p_ptr->resist_lite) - { - msg_print(_("日光があなたの肉体を焦がした!", "The sunlight scorches your flesh!")); - take_hit(DAMAGE_NOESCAPE, 50, _("日光", "sunlight"), -1); - } - } - } - break; - - case 30: - if (name) return _("精霊の刃", "Elemental Branding"); - if (desc) return _("武器に炎か冷気の属性をつける。", "Makes current weapon fire or frost branded."); - - { - if (cast) - { - brand_weapon(randint0(2)); - } - } - break; - - case 31: - if (name) return _("自然の脅威", "Nature's Wrath"); - if (desc) return _("近くの全てのモンスターにダメージを与え、地震を起こし、自分を中心とした分解の球を発生させる。", - "Damages all monsters in sight. Makes quake. Generates disintegration ball centered on you."); - - { - int d_dam = 4 * plev; - int b_dam = (100 + plev) * 2; - POSITION b_rad = 1 + plev / 12; - POSITION q_rad = 20 + plev / 2; - - if (info) return format("%s%d+%d", KWD_DAM, d_dam, b_dam / 2); - - if (cast) - { - dispel_monsters(d_dam); - earthquake(p_ptr->y, p_ptr->x, q_rad); - project(0, b_rad, p_ptr->y, p_ptr->x, b_dam, GF_DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM, -1); - } - } - break; - } - - return ""; -} - +#include "angband.h" +#include "cmd-spell.h" +#include "projection.h" +#include "spells-summon.h" +#include "spells-status.h" +#include "avatar.h" + + +/*! +* @brief 自然領域魔法の各処理を行う +* @param spell 魔法ID +* @param mode 処理内容 (SPELL_NAME / SPELL_DESC / SPELL_INFO / SPELL_CAST) +* @return SPELL_NAME / SPELL_DESC / SPELL_INFO 時には文字列ポインタを返す。SPELL_CAST時はNULL文字列を返す。 +*/ +concptr do_nature_spell(SPELL_IDX spell, BIT_FLAGS mode) +{ + bool name = (mode == SPELL_NAME) ? TRUE : FALSE; + bool desc = (mode == SPELL_DESC) ? TRUE : FALSE; + bool info = (mode == SPELL_INFO) ? TRUE : FALSE; + bool cast = (mode == SPELL_CAST) ? TRUE : FALSE; + + DIRECTION dir; + PLAYER_LEVEL plev = p_ptr->lev; + + switch (spell) + { + case 0: + if (name) return _("モンスター感知", "Detect Creatures"); + if (desc) return _("近くの全ての見えるモンスターを感知する。", "Detects all monsters in your vicinity unless invisible."); + + { + POSITION rad = DETECT_RAD_DEFAULT; + + if (info) return info_radius(rad); + + if (cast) + { + detect_monsters_normal(rad); + } + } + break; + + case 1: + if (name) return _("稲妻", "Lightning"); + if (desc) return _("電撃の短いビームを放つ。", "Fires a short beam of lightning."); + + { + DICE_NUMBER dice = 3 + (plev - 1) / 5; + DICE_SID sides = 4; + POSITION range = plev / 6 + 2; + + if (info) return format("%s%dd%d %s%d", KWD_DAM, dice, sides, KWD_RANGE, range); + + if (cast) + { + project_length = range; + + if (!get_aim_dir(&dir)) return NULL; + + fire_beam(GF_ELEC, dir, damroll(dice, sides)); + } + } + break; + + case 2: + if (name) return _("罠と扉感知", "Detect Doors and Traps"); + if (desc) return _("近くの全ての罠と扉を感知する。", "Detects traps, doors, and stairs in your vicinity."); + + { + POSITION rad = DETECT_RAD_DEFAULT; + + if (info) return info_radius(rad); + + if (cast) + { + detect_traps(rad, TRUE); + detect_doors(rad); + detect_stairs(rad); + } + } + break; + + case 3: + if (name) return _("食糧生成", "Produce Food"); + if (desc) return _("食料を一つ作り出す。", "Produces a Ration of Food."); + + { + if (cast) + { + object_type forge, *q_ptr = &forge; + msg_print(_("食料を生成した。", "A food ration is produced.")); + + /* Create the food ration */ + object_prep(q_ptr, lookup_kind(TV_FOOD, SV_FOOD_RATION)); + + /* Drop the object from heaven */ + (void)drop_near(q_ptr, -1, p_ptr->y, p_ptr->x); + } + } + break; + + case 4: + if (name) return _("日の光", "Daylight"); + if (desc) return _("光源が照らしている範囲か部屋全体を永久に明るくする。", "Lights up nearby area and the inside of a room permanently."); + + { + DICE_NUMBER dice = 2; + DICE_SID sides = plev / 2; + POSITION rad = (plev / 10) + 1; + + if (info) return info_damage(dice, sides, 0); + + if (cast) + { + lite_area(damroll(dice, sides), rad); + + if ((prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) && !p_ptr->resist_lite) + { + msg_print(_("日の光があなたの肉体を焦がした!", "The daylight scorches your flesh!")); + take_hit(DAMAGE_NOESCAPE, damroll(2, 2), _("日の光", "daylight"), -1); + } + } + } + break; + + case 5: + if (name) return _("動物習し", "Animal Taming"); + if (desc) return _("動物1体を魅了する。抵抗されると無効。", "Attempts to charm an animal."); + + { + int power = plev; + + if (info) return info_power(power); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + + charm_animal(dir, plev); + } + } + break; + + case 6: + if (name) return _("環境への耐性", "Resist Environment"); + if (desc) return _("一定時間、冷気、炎、電撃に対する耐性を得る。装備による耐性に累積する。", + "Gives resistance to fire, cold and electricity for a while. These resistances can be added to which from equipment for more powerful resistances."); + + { + int base = 20; + + if (info) return info_duration(base, base); + + if (cast) + { + set_oppose_cold(randint1(base) + base, FALSE); + set_oppose_fire(randint1(base) + base, FALSE); + set_oppose_elec(randint1(base) + base, FALSE); + } + } + break; + + case 7: + if (name) return _("傷と毒治療", "Cure Wounds & Poison"); + if (desc) return _("怪我を全快させ、毒を体から完全に取り除き、体力を少し回復させる。", "Heals all cut and poison status. Heals HP a little."); + + { + DICE_NUMBER dice = 2; + DICE_SID sides = 8; + + if (info) return info_heal(dice, sides, 0); + + if (cast) + { + hp_player(damroll(dice, sides)); + set_cut(0); + set_poisoned(0); + } + } + break; + + case 8: + if (name) return _("岩石溶解", "Stone to Mud"); + if (desc) return _("壁を溶かして床にする。", "Turns one rock square to mud."); + + { + DICE_NUMBER dice = 1; + DICE_SID sides = 30; + int base = 20; + + if (info) return info_damage(dice, sides, base); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + + wall_to_mud(dir, 20 + randint1(30)); + } + } + break; + + case 9: + if (name) return _("アイス・ボルト", "Frost Bolt"); + if (desc) return _("冷気のボルトもしくはビームを放つ。", "Fires a bolt or beam of cold."); + + { + DICE_NUMBER dice = 3 + (plev - 5) / 4; + DICE_SID sides = 8; + + if (info) return info_damage(dice, sides, 0); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + fire_bolt_or_beam(beam_chance() - 10, GF_COLD, dir, damroll(dice, sides)); + } + } + break; + + case 10: + if (name) return _("自然の覚醒", "Nature Awareness"); + if (desc) return _("周辺の地形を感知し、近くの罠、扉、階段、全てのモンスターを感知する。", + "Maps nearby area. Detects all monsters, traps, doors and stairs."); + + { + int rad1 = DETECT_RAD_MAP; + int rad2 = DETECT_RAD_DEFAULT; + + if (info) return info_radius(MAX(rad1, rad2)); + + if (cast) + { + map_area(rad1); + detect_traps(rad2, TRUE); + detect_doors(rad2); + detect_stairs(rad2); + detect_monsters_normal(rad2); + } + } + break; + + case 11: + if (name) return _("ファイア・ボルト", "Fire Bolt"); + if (desc) return _("火炎のボルトもしくはビームを放つ。", "Fires a bolt or beam of fire."); + + { + DICE_NUMBER dice = 5 + (plev - 5) / 4; + DICE_SID sides = 8; + + if (info) return info_damage(dice, sides, 0); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + fire_bolt_or_beam(beam_chance() - 10, GF_FIRE, dir, damroll(dice, sides)); + } + } + break; + + case 12: + if (name) return _("太陽光線", "Ray of Sunlight"); + if (desc) return _("光線を放つ。光りを嫌うモンスターに効果がある。", "Fires a beam of light which damages to light-sensitive monsters."); + + { + DICE_NUMBER dice = 6; + DICE_SID sides = 8; + + if (info) return info_damage(dice, sides, 0); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + msg_print(_("太陽光線が現れた。", "A line of sunlight appears.")); + lite_line(dir, damroll(6, 8)); + } + } + break; + + case 13: + if (name) return _("足かせ", "Entangle"); + if (desc) return _("視界内の全てのモンスターを減速させる。抵抗されると無効。", "Attempts to slow all monsters in sight."); + { + int power = plev; + if (info) return info_power(power); + if (cast) slow_monsters(plev); + } + break; + + case 14: + if (name) return _("動物召喚", "Summon Animal"); + if (desc) return _("動物を1体召喚する。", "Summons an animal."); + + { + if (cast) + { + if (!(summon_specific(-1, p_ptr->y, p_ptr->x, plev, SUMMON_ANIMAL_RANGER, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0'))) + { + msg_print(_("動物は現れなかった。", "No animals arrive.")); + } + break; + } + } + break; + + case 15: + if (name) return _("薬草治療", "Herbal Healing"); + if (desc) return _("体力を大幅に回復させ、負傷、朦朧状態、毒から全快する。", "Heals HP greatly. And heals cut, stun and poison completely."); + { + int heal = 500; + if (info) return info_heal(0, 0, heal); + if (cast) (void)cure_critical_wounds(heal); + } + break; + + case 16: + if (name) return _("階段生成", "Stair Building"); + if (desc) return _("自分のいる位置に階段を作る。", "Creates a stair which goes down or up."); + + { + if (cast) + { + stair_creation(); + } + } + break; + + case 17: + if (name) return _("肌石化", "Stone Skin"); + if (desc) return _("一定時間、ACを上昇させる。", "Gives bonus to AC for a while."); + + { + int base = 20; + DICE_SID sides = 30; + + if (info) return info_duration(base, sides); + + if (cast) + { + set_shield(randint1(sides) + base, FALSE); + } + } + break; + + case 18: + if (name) return _("真・耐性", "Resistance True"); + if (desc) return _("一定時間、酸、電撃、炎、冷気、毒に対する耐性を得る。装備による耐性に累積する。", + "Gives resistance to fire, cold, electricity, acid and poison for a while. These resistances can be added to which from equipment for more powerful resistances."); + + { + int base = 20; + + if (info) return info_duration(base, base); + + if (cast) + { + set_oppose_acid(randint1(base) + base, FALSE); + set_oppose_elec(randint1(base) + base, FALSE); + set_oppose_fire(randint1(base) + base, FALSE); + set_oppose_cold(randint1(base) + base, FALSE); + set_oppose_pois(randint1(base) + base, FALSE); + } + } + break; + + case 19: + if (name) return _("森林創造", "Forest Creation"); + if (desc) return _("周囲に木を作り出す。", "Creates trees in all adjacent squares."); + + { + if (cast) + { + tree_creation(); + } + } + break; + + case 20: + if (name) return _("動物友和", "Animal Friendship"); + if (desc) return _("視界内の全ての動物を魅了する。抵抗されると無効。", "Attempts to charm all animals in sight."); + + { + int power = plev * 2; + if (info) return info_power(power); + if (cast) charm_animals(power); + } + break; + + case 21: + if (name) return _("試金石", "Stone Tell"); + if (desc) return _("アイテムの持つ能力を完全に知る。", "*Identifies* an item."); + + { + if (cast) + { + if (!identify_fully(FALSE)) return NULL; + } + } + break; + + case 22: + if (name) return _("石の壁", "Wall of Stone"); + if (desc) return _("自分の周囲に花崗岩の壁を作る。", "Creates granite walls in all adjacent squares."); + + { + if (cast) + { + wall_stone(); + } + } + break; + + case 23: + if (name) return _("腐食防止", "Protect from Corrosion"); + if (desc) return _("アイテムを酸で傷つかないよう加工する。", "Makes an equipment acid-proof."); + + { + if (cast) + { + if (!rustproof()) return NULL; + } + } + break; + + case 24: + if (name) return _("地震", "Earthquake"); + if (desc) return _("周囲のダンジョンを揺らし、壁と床をランダムに入れ変える。", + "Shakes dungeon structure, and results in random swapping of floors and walls."); + + { + POSITION rad = 10; + + if (info) return info_radius(rad); + + if (cast) + { + earthquake(p_ptr->y, p_ptr->x, rad); + } + } + break; + + case 25: + if (name) return _("カマイタチ", "Whirlwind"); + if (desc) return _("全方向に向かって攻撃する。", "Attacks all adjacent monsters."); + if (cast) massacre(); + break; + + case 26: + if (name) return _("ブリザード", "Blizzard"); + if (desc) return _("巨大な冷気の球を放つ。", "Fires a huge ball of cold."); + + { + HIT_POINT dam = 70 + plev * 3 / 2; + POSITION rad = plev / 12 + 1; + + if (info) return info_damage(0, 0, dam); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + + fire_ball(GF_COLD, dir, dam, rad); + } + } + break; + + case 27: + if (name) return _("稲妻嵐", "Lightning Storm"); + if (desc) return _("巨大な電撃の球を放つ。", "Fires a huge electric ball."); + + { + HIT_POINT dam = 90 + plev * 3 / 2; + POSITION rad = plev / 12 + 1; + + if (info) return info_damage(0, 0, dam); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + fire_ball(GF_ELEC, dir, dam, rad); + break; + } + } + break; + + case 28: + if (name) return _("渦潮", "Whirlpool"); + if (desc) return _("巨大な水の球を放つ。", "Fires a huge ball of water."); + + { + HIT_POINT dam = 100 + plev * 3 / 2; + POSITION rad = plev / 12 + 1; + + if (info) return info_damage(0, 0, dam); + + if (cast) + { + if (!get_aim_dir(&dir)) return NULL; + fire_ball(GF_WATER, dir, dam, rad); + } + } + break; + + case 29: + if (name) return _("陽光召喚", "Call Sunlight"); + if (desc) return _("自分を中心とした光の球を発生させる。さらに、その階全体を永久に照らし、ダンジョン内すべてのアイテムを感知する。", + "Generates ball of light centered on you. Maps and lights whole dungeon level. Knows all objects location."); + + { + HIT_POINT dam = 150; + POSITION rad = 8; + + if (info) return info_damage(0, 0, dam / 2); + + if (cast) + { + fire_ball(GF_LITE, 0, dam, rad); + chg_virtue(V_KNOWLEDGE, 1); + chg_virtue(V_ENLIGHTEN, 1); + wiz_lite(FALSE); + + if ((prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) && !p_ptr->resist_lite) + { + msg_print(_("日光があなたの肉体を焦がした!", "The sunlight scorches your flesh!")); + take_hit(DAMAGE_NOESCAPE, 50, _("日光", "sunlight"), -1); + } + } + } + break; + + case 30: + if (name) return _("精霊の刃", "Elemental Branding"); + if (desc) return _("武器に炎か冷気の属性をつける。", "Makes current weapon fire or frost branded."); + + { + if (cast) + { + brand_weapon(randint0(2)); + } + } + break; + + case 31: + if (name) return _("自然の脅威", "Nature's Wrath"); + if (desc) return _("近くの全てのモンスターにダメージを与え、地震を起こし、自分を中心とした分解の球を発生させる。", + "Damages all monsters in sight. Makes quake. Generates disintegration ball centered on you."); + + { + int d_dam = 4 * plev; + int b_dam = (100 + plev) * 2; + POSITION b_rad = 1 + plev / 12; + POSITION q_rad = 20 + plev / 2; + + if (info) return format("%s%d+%d", KWD_DAM, d_dam, b_dam / 2); + + if (cast) + { + dispel_monsters(d_dam); + earthquake(p_ptr->y, p_ptr->x, q_rad); + project(0, b_rad, p_ptr->y, p_ptr->x, b_dam, GF_DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM, -1); + } + } + break; + } + + return ""; +} + diff --git a/src/realm-nature.h b/src/realm-nature.h index 031b44763..f3126a450 100644 --- a/src/realm-nature.h +++ b/src/realm-nature.h @@ -1 +1 @@ -extern concptr do_nature_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_nature_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-song.h b/src/realm-song.h index c92e1dbec..7642078f1 100644 --- a/src/realm-song.h +++ b/src/realm-song.h @@ -1 +1 @@ -extern concptr do_music_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_music_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-sorcery.h b/src/realm-sorcery.h index 1853a13f4..1767b61e7 100644 --- a/src/realm-sorcery.h +++ b/src/realm-sorcery.h @@ -1 +1 @@ -extern concptr do_sorcery_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_sorcery_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/realm-trump.h b/src/realm-trump.h index af1b6e25d..def707c2c 100644 --- a/src/realm-trump.h +++ b/src/realm-trump.h @@ -1 +1 @@ -extern concptr do_trump_spell(SPELL_IDX spell, BIT_FLAGS mode); +extern concptr do_trump_spell(SPELL_IDX spell, BIT_FLAGS mode); diff --git a/src/rooms-city.c b/src/rooms-city.c index a55ae5689..58b1ab018 100644 --- a/src/rooms-city.c +++ b/src/rooms-city.c @@ -1,259 +1,259 @@ -#include "angband.h" -#include "grid.h" -#include "generate.h" -#include "rooms.h" -#include "rooms-city.h" -#include "store.h" - - - -/* -* Precalculate buildings' location of underground arcade -*/ -static bool precalc_ugarcade(int town_hgt, int town_wid, int n) -{ - POSITION i, y, x, center_y, center_x; - int tmp, attempt = 10000; - POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT; - POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID; - ugbldg_type *cur_ugbldg; - bool **ugarcade_used, abort; - - /* Allocate "ugarcade_used" array (2-dimension) */ - C_MAKE(ugarcade_used, town_hgt, bool *); - C_MAKE(*ugarcade_used, town_hgt * town_wid, bool); - for (y = 1; y < town_hgt; y++) ugarcade_used[y] = *ugarcade_used + y * town_wid; - - /* Calculate building locations */ - for (i = 0; i < n; i++) - { - cur_ugbldg = &ugbldg[i]; - (void)WIPE(cur_ugbldg, ugbldg_type); - - do - { - /* Find the "center" of the store */ - center_y = rand_range(2, town_hgt - 3); - center_x = rand_range(2, town_wid - 3); - - /* Determine the store boundaries */ - tmp = center_y - randint1(max_bldg_hgt); - cur_ugbldg->y0 = MAX(tmp, 1); - tmp = center_x - randint1(max_bldg_wid); - cur_ugbldg->x0 = MAX(tmp, 1); - tmp = center_y + randint1(max_bldg_hgt); - cur_ugbldg->y1 = MIN(tmp, town_hgt - 2); - tmp = center_x + randint1(max_bldg_wid); - cur_ugbldg->x1 = MIN(tmp, town_wid - 2); - - /* Scan this building's area */ - for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) - { - for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) - { - if (ugarcade_used[y][x]) - { - abort = TRUE; - break; - } - } - } - - attempt--; - } while (abort && attempt); /* Accept this building if no overlapping */ - - /* Failed to generate underground arcade */ - if (!attempt) break; - - /* - * Mark to ugarcade_used[][] as "used" - * Note: Building-adjacent grids are included for preventing - * connected bulidings. - */ - for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++) - { - for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++) - { - ugarcade_used[y][x] = TRUE; - } - } - } - - /* Free "ugarcade_used" array (2-dimension) */ - C_KILL(*ugarcade_used, town_hgt * town_wid, bool); - C_KILL(ugarcade_used, town_hgt, bool *); - - /* If i < n, generation is not allowed */ - return i == n; -} - - -/*! -* @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings -* @return なし -* @param ltcy 生成基準Y座標 -* @param ltcx 生成基準X座標 -* @param stotes[] 生成する店舗のリスト -* @param n 生成する店舗の数 -* @note -* Note: ltcy and ltcx indicate "left top corner". -*/ -static void build_stores(POSITION ltcy, POSITION ltcx, int stores[], int n) -{ - int i; - POSITION y, x; - FEAT_IDX j; - ugbldg_type *cur_ugbldg; - - for (i = 0; i < n; i++) - { - cur_ugbldg = &ugbldg[i]; - - /* Generate new room */ - generate_room_floor( - ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2, - ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2, - FALSE); - } - - for (i = 0; i < n; i++) - { - cur_ugbldg = &ugbldg[i]; - - /* Build an invulnerable rectangular building */ - generate_fill_perm_bold( - ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0, - ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1); - - /* Pick a door direction (S,N,E,W) */ - switch (randint0(4)) - { - /* Bottom side */ - case 0: - y = cur_ugbldg->y1; - x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); - break; - - /* Top side */ - case 1: - y = cur_ugbldg->y0; - x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); - break; - - /* Right side */ - case 2: - y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); - x = cur_ugbldg->x1; - break; - - /* Left side */ - default: - y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); - x = cur_ugbldg->x0; - break; - } - - for (j = 0; j < max_f_idx; j++) - { - if (have_flag(f_info[j].flags, FF_STORE)) - { - if (f_info[j].subtype == stores[i]) break; - } - } - - /* Clear previous contents, add a store door */ - if (j < max_f_idx) - { - cave_set_feat(ltcy + y, ltcx + x, j); - - /* Init store */ - store_init(NO_TOWN, stores[i]); - } - } -} - - -/*! -* @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade -* @return なし -* @details -* Town logic flow for generation of new town\n -* Originally from Vanilla 3.0.3\n -*\n -* We start with a fully wiped cave of normal floors.\n -*\n -* Note that town_gen_hack() plays games with the R.N.G.\n -*\n -* This function does NOT do anything about the owners of the stores,\n -* nor the contents thereof. It only handles the physical layout.\n -*/ -bool build_type16(void) -{ - int stores[] = - { - STORE_GENERAL, STORE_ARMOURY, STORE_WEAPON, STORE_TEMPLE, - STORE_ALCHEMIST, STORE_MAGIC, STORE_BLACK, STORE_BOOK, - }; - int n = sizeof stores / sizeof(int); - POSITION i, y, x, y1, x1, yval, xval; - int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT); - int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID); - bool prevent_bm = FALSE; - - /* Hack -- If already exist black market, prevent building */ - for (y = 0; (y < cur_hgt) && !prevent_bm; y++) - { - for (x = 0; x < cur_wid; x++) - { - if (cave[y][x].feat == FF_STORE) - { - prevent_bm = (f_info[cave[y][x].feat].subtype == STORE_BLACK); - break; - } - } - } - for (i = 0; i < n; i++) - { - if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n]; - } - if (!n) return FALSE; - - /* Allocate buildings array */ - C_MAKE(ugbldg, n, ugbldg_type); - - /* If cannot build stores, abort */ - if (!precalc_ugarcade(town_hgt, town_wid, n)) - { - /* Free buildings array */ - C_KILL(ugbldg, n, ugbldg_type); - return FALSE; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, town_hgt + 4, town_wid + 4)) - { - /* Free buildings array */ - C_KILL(ugbldg, n, ugbldg_type); - return FALSE; - } - - /* Get top left corner */ - y1 = yval - (town_hgt / 2); - x1 = xval - (town_wid / 2); - - /* Generate new room */ - generate_room_floor( - y1 + town_hgt / 3, x1 + town_wid / 3, - y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE); - - /* Build stores */ - build_stores(y1, x1, stores, n); - - msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated.")); - - /* Free buildings array */ - C_KILL(ugbldg, n, ugbldg_type); - - return TRUE; -} - +#include "angband.h" +#include "grid.h" +#include "generate.h" +#include "rooms.h" +#include "rooms-city.h" +#include "store.h" + + + +/* +* Precalculate buildings' location of underground arcade +*/ +static bool precalc_ugarcade(int town_hgt, int town_wid, int n) +{ + POSITION i, y, x, center_y, center_x; + int tmp, attempt = 10000; + POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT; + POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID; + ugbldg_type *cur_ugbldg; + bool **ugarcade_used, abort; + + /* Allocate "ugarcade_used" array (2-dimension) */ + C_MAKE(ugarcade_used, town_hgt, bool *); + C_MAKE(*ugarcade_used, town_hgt * town_wid, bool); + for (y = 1; y < town_hgt; y++) ugarcade_used[y] = *ugarcade_used + y * town_wid; + + /* Calculate building locations */ + for (i = 0; i < n; i++) + { + cur_ugbldg = &ugbldg[i]; + (void)WIPE(cur_ugbldg, ugbldg_type); + + do + { + /* Find the "center" of the store */ + center_y = rand_range(2, town_hgt - 3); + center_x = rand_range(2, town_wid - 3); + + /* Determine the store boundaries */ + tmp = center_y - randint1(max_bldg_hgt); + cur_ugbldg->y0 = MAX(tmp, 1); + tmp = center_x - randint1(max_bldg_wid); + cur_ugbldg->x0 = MAX(tmp, 1); + tmp = center_y + randint1(max_bldg_hgt); + cur_ugbldg->y1 = MIN(tmp, town_hgt - 2); + tmp = center_x + randint1(max_bldg_wid); + cur_ugbldg->x1 = MIN(tmp, town_wid - 2); + + /* Scan this building's area */ + for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) + { + for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) + { + if (ugarcade_used[y][x]) + { + abort = TRUE; + break; + } + } + } + + attempt--; + } while (abort && attempt); /* Accept this building if no overlapping */ + + /* Failed to generate underground arcade */ + if (!attempt) break; + + /* + * Mark to ugarcade_used[][] as "used" + * Note: Building-adjacent grids are included for preventing + * connected bulidings. + */ + for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++) + { + for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++) + { + ugarcade_used[y][x] = TRUE; + } + } + } + + /* Free "ugarcade_used" array (2-dimension) */ + C_KILL(*ugarcade_used, town_hgt * town_wid, bool); + C_KILL(ugarcade_used, town_hgt, bool *); + + /* If i < n, generation is not allowed */ + return i == n; +} + + +/*! +* @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings +* @return なし +* @param ltcy 生成基準Y座標 +* @param ltcx 生成基準X座標 +* @param stotes[] 生成する店舗のリスト +* @param n 生成する店舗の数 +* @note +* Note: ltcy and ltcx indicate "left top corner". +*/ +static void build_stores(POSITION ltcy, POSITION ltcx, int stores[], int n) +{ + int i; + POSITION y, x; + FEAT_IDX j; + ugbldg_type *cur_ugbldg; + + for (i = 0; i < n; i++) + { + cur_ugbldg = &ugbldg[i]; + + /* Generate new room */ + generate_room_floor( + ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2, + ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2, + FALSE); + } + + for (i = 0; i < n; i++) + { + cur_ugbldg = &ugbldg[i]; + + /* Build an invulnerable rectangular building */ + generate_fill_perm_bold( + ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0, + ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1); + + /* Pick a door direction (S,N,E,W) */ + switch (randint0(4)) + { + /* Bottom side */ + case 0: + y = cur_ugbldg->y1; + x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); + break; + + /* Top side */ + case 1: + y = cur_ugbldg->y0; + x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); + break; + + /* Right side */ + case 2: + y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); + x = cur_ugbldg->x1; + break; + + /* Left side */ + default: + y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); + x = cur_ugbldg->x0; + break; + } + + for (j = 0; j < max_f_idx; j++) + { + if (have_flag(f_info[j].flags, FF_STORE)) + { + if (f_info[j].subtype == stores[i]) break; + } + } + + /* Clear previous contents, add a store door */ + if (j < max_f_idx) + { + cave_set_feat(ltcy + y, ltcx + x, j); + + /* Init store */ + store_init(NO_TOWN, stores[i]); + } + } +} + + +/*! +* @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade +* @return なし +* @details +* Town logic flow for generation of new town\n +* Originally from Vanilla 3.0.3\n +*\n +* We start with a fully wiped cave of normal floors.\n +*\n +* Note that town_gen_hack() plays games with the R.N.G.\n +*\n +* This function does NOT do anything about the owners of the stores,\n +* nor the contents thereof. It only handles the physical layout.\n +*/ +bool build_type16(void) +{ + int stores[] = + { + STORE_GENERAL, STORE_ARMOURY, STORE_WEAPON, STORE_TEMPLE, + STORE_ALCHEMIST, STORE_MAGIC, STORE_BLACK, STORE_BOOK, + }; + int n = sizeof stores / sizeof(int); + POSITION i, y, x, y1, x1, yval, xval; + int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT); + int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID); + bool prevent_bm = FALSE; + + /* Hack -- If already exist black market, prevent building */ + for (y = 0; (y < cur_hgt) && !prevent_bm; y++) + { + for (x = 0; x < cur_wid; x++) + { + if (cave[y][x].feat == FF_STORE) + { + prevent_bm = (f_info[cave[y][x].feat].subtype == STORE_BLACK); + break; + } + } + } + for (i = 0; i < n; i++) + { + if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n]; + } + if (!n) return FALSE; + + /* Allocate buildings array */ + C_MAKE(ugbldg, n, ugbldg_type); + + /* If cannot build stores, abort */ + if (!precalc_ugarcade(town_hgt, town_wid, n)) + { + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); + return FALSE; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, town_hgt + 4, town_wid + 4)) + { + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); + return FALSE; + } + + /* Get top left corner */ + y1 = yval - (town_hgt / 2); + x1 = xval - (town_wid / 2); + + /* Generate new room */ + generate_room_floor( + y1 + town_hgt / 3, x1 + town_wid / 3, + y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE); + + /* Build stores */ + build_stores(y1, x1, stores, n); + + msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated.")); + + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); + + return TRUE; +} + diff --git a/src/rooms-city.h b/src/rooms-city.h index e4acf7004..a838f7d8f 100644 --- a/src/rooms-city.h +++ b/src/rooms-city.h @@ -1,17 +1,17 @@ -extern bool build_type16(void); - -/* Minimum & maximum town size */ -#define MIN_TOWN_WID ((MAX_WID / 3) / 2) -#define MIN_TOWN_HGT ((MAX_HGT / 3) / 2) -#define MAX_TOWN_WID ((MAX_WID / 3) * 2 / 3) -#define MAX_TOWN_HGT ((MAX_HGT / 3) * 2 / 3) - -/* Struct for build underground buildings */ -typedef struct -{ - POSITION y0, x0; /* North-west corner (relative) */ - POSITION y1, x1; /* South-east corner (relative) */ -} -ugbldg_type; - -ugbldg_type *ugbldg; +extern bool build_type16(void); + +/* Minimum & maximum town size */ +#define MIN_TOWN_WID ((MAX_WID / 3) / 2) +#define MIN_TOWN_HGT ((MAX_HGT / 3) / 2) +#define MAX_TOWN_WID ((MAX_WID / 3) * 2 / 3) +#define MAX_TOWN_HGT ((MAX_HGT / 3) * 2 / 3) + +/* Struct for build underground buildings */ +typedef struct +{ + POSITION y0, x0; /* North-west corner (relative) */ + POSITION y1, x1; /* South-east corner (relative) */ +} +ugbldg_type; + +ugbldg_type *ugbldg; diff --git a/src/rooms-fractal.c b/src/rooms-fractal.c index 858c7d27c..de054776a 100644 --- a/src/rooms-fractal.c +++ b/src/rooms-fractal.c @@ -1,68 +1,68 @@ -#include "angband.h" -#include "grid.h" -#include "generate.h" -#include "rooms.h" -#include "rooms-normal.h" - -/*! -* @brief タイプ9の部屋…フラクタルカーブによる洞窟生成 / Type 9 -- Driver routine to create fractal cave system -* @return なし -*/ -bool build_type9(void) -{ - int grd, roug, cutoff; - POSITION xsize, ysize, y0, x0; - - bool done, light, room; - - /* get size: note 'Evenness'*/ - xsize = randint1(22) * 2 + 6; - ysize = randint1(15) * 2 + 6; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) - { - /* Limit to the minimum room size, and retry */ - xsize = 8; - ysize = 8; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) - { - /* - * Still no space?! - * Try normal room - */ - return build_type1(); - } - } - - light = done = FALSE; - room = TRUE; - - if ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; - - while (!done) - { - /* Note: size must be even or there are rounding problems - * This causes the tunnels not to connect properly to the room */ - - /* testing values for these parameters feel free to adjust */ - grd = 1 << (randint0(4)); - - /* want average of about 16 */ - roug = randint1(8) * randint1(4); - - /* about size/2 */ - cutoff = randint1(xsize / 4) + randint1(ysize / 4) + - randint1(xsize / 4) + randint1(ysize / 4); - - /* make it */ - generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff); - - /* Convert to normal format + clean up */ - done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room); - } - - return TRUE; -} +#include "angband.h" +#include "grid.h" +#include "generate.h" +#include "rooms.h" +#include "rooms-normal.h" + +/*! +* @brief タイプ9の部屋…フラクタルカーブによる洞窟生成 / Type 9 -- Driver routine to create fractal cave system +* @return なし +*/ +bool build_type9(void) +{ + int grd, roug, cutoff; + POSITION xsize, ysize, y0, x0; + + bool done, light, room; + + /* get size: note 'Evenness'*/ + xsize = randint1(22) * 2 + 6; + ysize = randint1(15) * 2 + 6; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) + { + /* Limit to the minimum room size, and retry */ + xsize = 8; + ysize = 8; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) + { + /* + * Still no space?! + * Try normal room + */ + return build_type1(); + } + } + + light = done = FALSE; + room = TRUE; + + if ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; + + while (!done) + { + /* Note: size must be even or there are rounding problems + * This causes the tunnels not to connect properly to the room */ + + /* testing values for these parameters feel free to adjust */ + grd = 1 << (randint0(4)); + + /* want average of about 16 */ + roug = randint1(8) * randint1(4); + + /* about size/2 */ + cutoff = randint1(xsize / 4) + randint1(ysize / 4) + + randint1(xsize / 4) + randint1(ysize / 4); + + /* make it */ + generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff); + + /* Convert to normal format + clean up */ + done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room); + } + + return TRUE; +} diff --git a/src/rooms-fractal.h b/src/rooms-fractal.h index 2c8d1913a..090e4e0a7 100644 --- a/src/rooms-fractal.h +++ b/src/rooms-fractal.h @@ -1,2 +1,2 @@ - -extern bool build_type9(void); + +extern bool build_type9(void); diff --git a/src/rooms-normal.c b/src/rooms-normal.c index 2c4703d08..28e9a9b66 100644 --- a/src/rooms-normal.c +++ b/src/rooms-normal.c @@ -1,1047 +1,1047 @@ -#include "angband.h" -#include "grid.h" -#include "trap.h" - -#include "rooms.h" - - -/*! -* @brief タイプ1の部屋…通常可変長方形の部屋を生成する / Type 1 -- normal rectangular rooms -* @return なし -*/ -bool build_type1(void) -{ - POSITION y, x, y2, x2, yval, xval; - POSITION y1, x1, xsize, ysize; - - bool light; - - cave_type *c_ptr; - - bool curtain = (d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && - one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 48 : 512); - - /* Pick a room size */ - y1 = randint1(4); - x1 = randint1(11); - y2 = randint1(3); - x2 = randint1(11); - - xsize = x1 + x2 + 1; - ysize = y1 + y2 + 1; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) - { - /* Limit to the minimum room size, and retry */ - y1 = 1; - x1 = 1; - y2 = 1; - x2 = 1; - - xsize = x1 + x2 + 1; - ysize = y1 + y2 + 1; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; - } - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - - /* Get corner values */ - y1 = yval - ysize / 2; - x1 = xval - xsize / 2; - y2 = yval + (ysize - 1) / 2; - x2 = xval + (xsize - 1) / 2; - - - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Walls around the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - - /* Hack -- Occasional curtained room */ - if (curtain && (y2 - y1 > 2) && (x2 - x1 > 2)) - { - for (y = y1; y <= y2; y++) - { - c_ptr = &cave[y][x1]; - c_ptr->feat = feat_door[DOOR_CURTAIN].closed; - c_ptr->info &= ~(CAVE_MASK); - c_ptr = &cave[y][x2]; - c_ptr->feat = feat_door[DOOR_CURTAIN].closed; - c_ptr->info &= ~(CAVE_MASK); - } - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[y1][x]; - c_ptr->feat = feat_door[DOOR_CURTAIN].closed; - c_ptr->info &= ~(CAVE_MASK); - c_ptr = &cave[y2][x]; - c_ptr->feat = feat_door[DOOR_CURTAIN].closed; - c_ptr->info &= ~(CAVE_MASK); - } - } - - - /* Hack -- Occasional pillar room */ - if (one_in_(20)) - { - for (y = y1; y <= y2; y += 2) - { - for (x = x1; x <= x2; x += 2) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - } - - /* Hack -- Occasional room with four pillars */ - else if (one_in_(20)) - { - if ((y1 + 4 < y2) && (x1 + 4 < x2)) - { - c_ptr = &cave[y1 + 1][x1 + 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y1 + 1][x2 - 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y2 - 1][x1 + 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y2 - 1][x2 - 1]; - place_inner_grid(c_ptr); - } - } - - /* Hack -- Occasional ragged-edge room */ - else if (one_in_(50)) - { - for (y = y1 + 2; y <= y2 - 2; y += 2) - { - c_ptr = &cave[y][x1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2]; - place_inner_grid(c_ptr); - } - for (x = x1 + 2; x <= x2 - 2; x += 2) - { - c_ptr = &cave[y1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2][x]; - place_inner_grid(c_ptr); - } - } - /* Hack -- Occasional divided room */ - else if (one_in_(50)) - { - bool curtain2 = (d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && - one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 2 : 128); - - if (randint1(100) < 50) - { - /* Horizontal wall */ - for (x = x1; x <= x2; x++) - { - place_inner_bold(yval, x); - if (curtain2) cave[yval][x].feat = feat_door[DOOR_CURTAIN].closed; - } - - /* Prevent edge of wall from being tunneled */ - place_solid_bold(yval, x1 - 1); - place_solid_bold(yval, x2 + 1); - } - else - { - /* Vertical wall */ - for (y = y1; y <= y2; y++) - { - place_inner_bold(y, xval); - if (curtain2) cave[y][xval].feat = feat_door[DOOR_CURTAIN].closed; - } - - /* Prevent edge of wall from being tunneled */ - place_solid_bold(y1 - 1, xval); - place_solid_bold(y2 + 1, xval); - } - - place_random_door(yval, xval, TRUE); - if (curtain2) cave[yval][xval].feat = feat_door[DOOR_CURTAIN].closed; - } - - return TRUE; -} - -/*! -* @brief タイプ2の部屋…二重長方形の部屋を生成する / Type 2 -- Overlapping rectangular rooms -* @return なし -*/ -bool build_type2(void) -{ - POSITION y, x, xval, yval; - POSITION y1a, x1a, y2a, x2a; - POSITION y1b, x1b, y2b, x2b; - bool light; - cave_type *c_ptr; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 11, 25)) return FALSE; - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - /* Determine extents of the first room */ - y1a = yval - randint1(4); - y2a = yval + randint1(3); - x1a = xval - randint1(11); - x2a = xval + randint1(10); - - /* Determine extents of the second room */ - y1b = yval - randint1(3); - y2b = yval + randint1(4); - x1b = xval - randint1(10); - x2b = xval + randint1(11); - - - /* Place a full floor for room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Place a full floor for room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - - /* Place the walls around room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - c_ptr = &cave[y][x1a - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_outer_grid(c_ptr); - } - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y1a - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2a + 1][x]; - place_outer_grid(c_ptr); - } - - /* Place the walls around room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - c_ptr = &cave[y][x1b - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2b + 1]; - place_outer_grid(c_ptr); - } - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y1b - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_outer_grid(c_ptr); - } - - - - /* Replace the floor for room "a" */ - for (y = y1a; y <= y2a; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } - - /* Replace the floor for room "b" */ - for (y = y1b; y <= y2b; y++) - { - for (x = x1b; x <= x2b; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } - - return TRUE; -} - -/*! -* @brief タイプ3の部屋…十字型の部屋を生成する / Type 3 -- Cross shaped rooms -* @return なし -* @details -* Builds a room at a row, column coordinate\n -*\n -* Room "a" runs north/south, and Room "b" runs east/east\n -* So the "central pillar" runs from x1a, y1b to x2a, y2b.\n -*\n -* Note that currently, the "center" is always 3x3, but I think that\n -* the code below will work (with "bounds checking") for 5x5, or even\n -* for unsymetric values like 4x3 or 5x3 or 3x4 or 3x5, or even larger.\n -*/ -bool build_type3(void) -{ - POSITION y, x, dy, dx, wy, wx; - POSITION y1a, x1a, y2a, x2a; - POSITION y1b, x1b, y2b, x2b; - POSITION yval, xval; - bool light; - cave_type *c_ptr; - - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 11, 25)) return FALSE; - - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - /* For now, always 3x3 */ - wx = wy = 1; - - /* Pick max vertical size (at most 4) */ - dy = rand_range(3, 4); - - /* Pick max horizontal size (at most 15) */ - dx = rand_range(3, 11); - - - /* Determine extents of the north/south room */ - y1a = yval - dy; - y2a = yval + dy; - x1a = xval - wx; - x2a = xval + wx; - - /* Determine extents of the east/west room */ - y1b = yval - wy; - y2b = yval + wy; - x1b = xval - dx; - x2b = xval + dx; - - - /* Place a full floor for room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Place a full floor for room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - - /* Place the walls around room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - c_ptr = &cave[y][x1a - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_outer_grid(c_ptr); - } - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y1a - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2a + 1][x]; - place_outer_grid(c_ptr); - } - - /* Place the walls around room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - c_ptr = &cave[y][x1b - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2b + 1]; - place_outer_grid(c_ptr); - } - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y1b - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_outer_grid(c_ptr); - } - - - /* Replace the floor for room "a" */ - for (y = y1a; y <= y2a; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } - - /* Replace the floor for room "b" */ - for (y = y1b; y <= y2b; y++) - { - for (x = x1b; x <= x2b; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } - - - - /* Special features (3/4) */ - switch (randint0(4)) - { - /* Large solid middle pillar */ - case 1: - { - for (y = y1b; y <= y2b; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - break; - } - - /* Inner treasure vault */ - case 2: - { - /* Build the vault */ - for (y = y1b; y <= y2b; y++) - { - c_ptr = &cave[y][x1a]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2a]; - place_inner_grid(c_ptr); - } - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y1b][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b][x]; - place_inner_grid(c_ptr); - } - - /* Place a secret door on the inner room */ - switch (randint0(4)) - { - case 0: place_secret_door(y1b, xval, DOOR_DEFAULT); break; - case 1: place_secret_door(y2b, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(yval, x1a, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x2a, DOOR_DEFAULT); break; - } - - /* Place a treasure in the vault */ - place_object(yval, xval, 0L); - - /* Let's guard the treasure well */ - vault_monsters(yval, xval, randint0(2) + 3); - - /* Traps naturally */ - vault_traps(yval, xval, 4, 4, randint0(3) + 2); - - break; - } - - /* Something else */ - case 3: - { - /* Occasionally pinch the center shut */ - if (one_in_(3)) - { - /* Pinch the east/west sides */ - for (y = y1b; y <= y2b; y++) - { - if (y == yval) continue; - c_ptr = &cave[y][x1a - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_inner_grid(c_ptr); - } - - /* Pinch the north/south sides */ - for (x = x1a; x <= x2a; x++) - { - if (x == xval) continue; - c_ptr = &cave[y1b - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_inner_grid(c_ptr); - } - - /* Sometimes shut using secret doors */ - if (one_in_(3)) - { - int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && - one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : - ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); - - place_secret_door(yval, x1a - 1, door_type); - place_secret_door(yval, x2a + 1, door_type); - place_secret_door(y1b - 1, xval, door_type); - place_secret_door(y2b + 1, xval, door_type); - } - } - - /* Occasionally put a "plus" in the center */ - else if (one_in_(3)) - { - c_ptr = &cave[yval][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[y1b][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][x1a]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][x2a]; - place_inner_grid(c_ptr); - } - - /* Occasionally put a pillar in the center */ - else if (one_in_(3)) - { - c_ptr = &cave[yval][xval]; - place_inner_grid(c_ptr); - } - - break; - } - } - - return TRUE; -} - -/*! -* @brief タイプ4の部屋…固定サイズの二重構造部屋を生成する / Type 4 -- Large room with inner features -* @return なし -* @details -* Possible sub-types:\n -* 1 - Just an inner room with one door\n -* 2 - An inner room within an inner room\n -* 3 - An inner room with pillar(s)\n -* 4 - Inner room has a maze\n -* 5 - A set of four inner rooms\n -*/ -bool build_type4(void) -{ - POSITION y, x, y1, x1; - POSITION y2, x2, tmp, yval, xval; - bool light; - cave_type *c_ptr; - - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 11, 25)) return FALSE; - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - /* Large room */ - y1 = yval - 4; - y2 = yval + 4; - x1 = xval - 11; - x2 = xval + 11; - - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Outer Walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - - /* The inner room */ - y1 = y1 + 2; - y2 = y2 - 2; - x1 = x1 + 2; - x2 = x2 - 2; - - /* The inner walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_inner_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_inner_grid(c_ptr); - } - - - /* Inner room variations */ - switch (randint1(5)) - { - /* Just an inner room with a monster */ - case 1: - { - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - /* Place a monster in the room */ - vault_monsters(yval, xval, 1); - - break; - } - - /* Treasure Vault (with a door) */ - case 2: - { - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - /* Place another inner room */ - for (y = yval - 1; y <= yval + 1; y++) - { - for (x = xval - 1; x <= xval + 1; x++) - { - if ((x == xval) && (y == yval)) continue; - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - - /* Place a locked door on the inner room */ - switch (randint1(4)) - { - case 1: place_locked_door(yval - 1, xval); break; - case 2: place_locked_door(yval + 1, xval); break; - case 3: place_locked_door(yval, xval - 1); break; - case 4: place_locked_door(yval, xval + 1); break; - } - - /* Monsters to guard the "treasure" */ - vault_monsters(yval, xval, randint1(3) + 2); - - /* Object (80%) */ - if (randint0(100) < 80) - { - place_object(yval, xval, 0L); - } - - /* Stairs (20%) */ - else - { - place_random_stairs(yval, xval); - } - - /* Traps to protect the treasure */ - vault_traps(yval, xval, 4, 10, 2 + randint1(3)); - - break; - } - - /* Inner pillar(s). */ - case 3: - { - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - /* Large Inner Pillar */ - for (y = yval - 1; y <= yval + 1; y++) - { - for (x = xval - 1; x <= xval + 1; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - - /* Occasionally, two more Large Inner Pillars */ - if (one_in_(2)) - { - tmp = randint1(2); - for (y = yval - 1; y <= yval + 1; y++) - { - for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - } - - /* Occasionally, some Inner rooms */ - if (one_in_(3)) - { - int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && - one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : - ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); - - /* Long horizontal walls */ - for (x = xval - 5; x <= xval + 5; x++) - { - c_ptr = &cave[yval - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval + 1][x]; - place_inner_grid(c_ptr); - } - - /* Close off the left/right edges */ - c_ptr = &cave[yval][xval - 5]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][xval + 5]; - place_inner_grid(c_ptr); - - /* Secret doors (random top/bottom) */ - place_secret_door(yval - 3 + (randint1(2) * 2), xval - 3, door_type); - place_secret_door(yval - 3 + (randint1(2) * 2), xval + 3, door_type); - - /* Monsters */ - vault_monsters(yval, xval - 2, randint1(2)); - vault_monsters(yval, xval + 2, randint1(2)); - - /* Objects */ - if (one_in_(3)) place_object(yval, xval - 2, 0L); - if (one_in_(3)) place_object(yval, xval + 2, 0L); - } - - break; - } - - /* Maze inside. */ - case 4: - { - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - /* Maze (really a checkerboard) */ - for (y = y1; y <= y2; y++) - { - for (x = x1; x <= x2; x++) - { - if (0x1 & (x + y)) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - } - - /* Monsters just love mazes. */ - vault_monsters(yval, xval - 5, randint1(3)); - vault_monsters(yval, xval + 5, randint1(3)); - - /* Traps make them entertaining. */ - vault_traps(yval, xval - 3, 2, 8, randint1(3)); - vault_traps(yval, xval + 3, 2, 8, randint1(3)); - - /* Mazes should have some treasure too. */ - vault_objects(yval, xval, 3); - - break; - } - - /* Four small rooms. */ - case 5: - { - int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && - one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : - ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); - - /* Inner "cross" */ - for (y = y1; y <= y2; y++) - { - c_ptr = &cave[y][xval]; - place_inner_grid(c_ptr); - } - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[yval][x]; - place_inner_grid(c_ptr); - } - - /* Doors into the rooms */ - if (randint0(100) < 50) - { - int i = randint1(10); - place_secret_door(y1 - 1, xval - i, door_type); - place_secret_door(y1 - 1, xval + i, door_type); - place_secret_door(y2 + 1, xval - i, door_type); - place_secret_door(y2 + 1, xval + i, door_type); - } - else - { - int i = randint1(3); - place_secret_door(yval + i, x1 - 1, door_type); - place_secret_door(yval - i, x1 - 1, door_type); - place_secret_door(yval + i, x2 + 1, door_type); - place_secret_door(yval - i, x2 + 1, door_type); - } - - /* Treasure, centered at the center of the cross */ - vault_objects(yval, xval, 2 + randint1(2)); - - /* Gotta have some monsters. */ - vault_monsters(yval + 1, xval - 4, randint1(4)); - vault_monsters(yval + 1, xval + 4, randint1(4)); - vault_monsters(yval - 1, xval - 4, randint1(4)); - vault_monsters(yval - 1, xval + 4, randint1(4)); - - break; - } - } - - return TRUE; -} - - -/*! -* @brief タイプ11の部屋…円形部屋の生成 / Type 11 -- Build an vertical oval room. -* @return なし -* @details -* For every grid in the possible square, check the distance.\n -* If it's less than the radius, make it a room square.\n -*\n -* When done fill from the inside to find the walls,\n -*/ -bool build_type11(void) -{ - POSITION rad, x, y, x0, y0; - int light = FALSE; - - /* Occasional light */ - if ((randint1(dun_level) <= 15) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; - - rad = randint0(9); - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&y0, &x0, rad * 2 + 1, rad * 2 + 1)) return FALSE; - - /* Make circular floor */ - for (x = x0 - rad; x <= x0 + rad; x++) - { - for (y = y0 - rad; y <= y0 + rad; y++) - { - if (distance(y0, x0, y, x) <= rad - 1) - { - /* inside- so is floor */ - place_floor_bold(y, x); - } - else if (distance(y0, x0, y, x) <= rad + 1) - { - /* make granite outside so arena works */ - place_extra_bold(y, x); - } - } - } - - /* Find visible outer walls and set to be FEAT_OUTER */ - add_outer_wall(x0, y0, light, x0 - rad, y0 - rad, x0 + rad, y0 + rad); - - return TRUE; -} - - -/*! -* @brief タイプ12の部屋…ドーム型部屋の生成 / Type 12 -- Build crypt room. -* @return なし -* @details -* For every grid in the possible square, check the (fake) distance.\n -* If it's less than the radius, make it a room square.\n -*\n -* When done fill from the inside to find the walls,\n -*/ -bool build_type12(void) -{ - POSITION rad, x, y, x0, y0; - int light = FALSE; - bool emptyflag = TRUE; - - /* Make a random metric */ - POSITION h1, h2, h3, h4; - h1 = randint1(32) - 16; - h2 = randint1(16); - h3 = randint1(32); - h4 = randint1(32) - 16; - - /* Occasional light */ - if ((randint1(dun_level) <= 5) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; - - rad = randint1(9); - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&y0, &x0, rad * 2 + 3, rad * 2 + 3)) return FALSE; - - /* Make floor */ - for (x = x0 - rad; x <= x0 + rad; x++) - { - for (y = y0 - rad; y <= y0 + rad; y++) - { - /* clear room flag */ - cave[y][x].info &= ~(CAVE_ROOM); - - if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) - { - /* inside - so is floor */ - place_floor_bold(y, x); - } - else if (distance(y0, x0, y, x) < 3) - { - place_floor_bold(y, x); - } - else - { - /* make granite outside so arena works */ - place_extra_bold(y, x); - } - - /* proper boundary for arena */ - if (((y + rad) == y0) || ((y - rad) == y0) || - ((x + rad) == x0) || ((x - rad) == x0)) - { - place_extra_bold(y, x); - } - } - } - - /* Find visible outer walls and set to be FEAT_OUTER */ - add_outer_wall(x0, y0, light, x0 - rad - 1, y0 - rad - 1, - x0 + rad + 1, y0 + rad + 1); - - /* Check to see if there is room for an inner vault */ - for (x = x0 - 2; x <= x0 + 2; x++) - { - for (y = y0 - 2; y <= y0 + 2; y++) - { - if (!is_floor_bold(y, x)) - { - /* Wall in the way */ - emptyflag = FALSE; - } - } - } - - if (emptyflag && one_in_(2)) - { - /* Build the vault */ - build_small_room(x0, y0); - - /* Place a treasure in the vault */ - place_object(y0, x0, 0L); - - /* Let's guard the treasure well */ - vault_monsters(y0, x0, randint0(2) + 3); - - /* Traps naturally */ - vault_traps(y0, x0, 4, 4, randint0(3) + 2); - } - - return TRUE; -} - +#include "angband.h" +#include "grid.h" +#include "trap.h" + +#include "rooms.h" + + +/*! +* @brief タイプ1の部屋…通常可変長方形の部屋を生成する / Type 1 -- normal rectangular rooms +* @return なし +*/ +bool build_type1(void) +{ + POSITION y, x, y2, x2, yval, xval; + POSITION y1, x1, xsize, ysize; + + bool light; + + cave_type *c_ptr; + + bool curtain = (d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && + one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 48 : 512); + + /* Pick a room size */ + y1 = randint1(4); + x1 = randint1(11); + y2 = randint1(3); + x2 = randint1(11); + + xsize = x1 + x2 + 1; + ysize = y1 + y2 + 1; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) + { + /* Limit to the minimum room size, and retry */ + y1 = 1; + x1 = 1; + y2 = 1; + x2 = 1; + + xsize = x1 + x2 + 1; + ysize = y1 + y2 + 1; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; + } + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + + /* Get corner values */ + y1 = yval - ysize / 2; + x1 = xval - xsize / 2; + y2 = yval + (ysize - 1) / 2; + x2 = xval + (xsize - 1) / 2; + + + /* Place a full floor under the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Walls around the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + + /* Hack -- Occasional curtained room */ + if (curtain && (y2 - y1 > 2) && (x2 - x1 > 2)) + { + for (y = y1; y <= y2; y++) + { + c_ptr = &cave[y][x1]; + c_ptr->feat = feat_door[DOOR_CURTAIN].closed; + c_ptr->info &= ~(CAVE_MASK); + c_ptr = &cave[y][x2]; + c_ptr->feat = feat_door[DOOR_CURTAIN].closed; + c_ptr->info &= ~(CAVE_MASK); + } + for (x = x1; x <= x2; x++) + { + c_ptr = &cave[y1][x]; + c_ptr->feat = feat_door[DOOR_CURTAIN].closed; + c_ptr->info &= ~(CAVE_MASK); + c_ptr = &cave[y2][x]; + c_ptr->feat = feat_door[DOOR_CURTAIN].closed; + c_ptr->info &= ~(CAVE_MASK); + } + } + + + /* Hack -- Occasional pillar room */ + if (one_in_(20)) + { + for (y = y1; y <= y2; y += 2) + { + for (x = x1; x <= x2; x += 2) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + } + + /* Hack -- Occasional room with four pillars */ + else if (one_in_(20)) + { + if ((y1 + 4 < y2) && (x1 + 4 < x2)) + { + c_ptr = &cave[y1 + 1][x1 + 1]; + place_inner_grid(c_ptr); + + c_ptr = &cave[y1 + 1][x2 - 1]; + place_inner_grid(c_ptr); + + c_ptr = &cave[y2 - 1][x1 + 1]; + place_inner_grid(c_ptr); + + c_ptr = &cave[y2 - 1][x2 - 1]; + place_inner_grid(c_ptr); + } + } + + /* Hack -- Occasional ragged-edge room */ + else if (one_in_(50)) + { + for (y = y1 + 2; y <= y2 - 2; y += 2) + { + c_ptr = &cave[y][x1]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2]; + place_inner_grid(c_ptr); + } + for (x = x1 + 2; x <= x2 - 2; x += 2) + { + c_ptr = &cave[y1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2][x]; + place_inner_grid(c_ptr); + } + } + /* Hack -- Occasional divided room */ + else if (one_in_(50)) + { + bool curtain2 = (d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && + one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 2 : 128); + + if (randint1(100) < 50) + { + /* Horizontal wall */ + for (x = x1; x <= x2; x++) + { + place_inner_bold(yval, x); + if (curtain2) cave[yval][x].feat = feat_door[DOOR_CURTAIN].closed; + } + + /* Prevent edge of wall from being tunneled */ + place_solid_bold(yval, x1 - 1); + place_solid_bold(yval, x2 + 1); + } + else + { + /* Vertical wall */ + for (y = y1; y <= y2; y++) + { + place_inner_bold(y, xval); + if (curtain2) cave[y][xval].feat = feat_door[DOOR_CURTAIN].closed; + } + + /* Prevent edge of wall from being tunneled */ + place_solid_bold(y1 - 1, xval); + place_solid_bold(y2 + 1, xval); + } + + place_random_door(yval, xval, TRUE); + if (curtain2) cave[yval][xval].feat = feat_door[DOOR_CURTAIN].closed; + } + + return TRUE; +} + +/*! +* @brief タイプ2の部屋…二重長方形の部屋を生成する / Type 2 -- Overlapping rectangular rooms +* @return なし +*/ +bool build_type2(void) +{ + POSITION y, x, xval, yval; + POSITION y1a, x1a, y2a, x2a; + POSITION y1b, x1b, y2b, x2b; + bool light; + cave_type *c_ptr; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + /* Determine extents of the first room */ + y1a = yval - randint1(4); + y2a = yval + randint1(3); + x1a = xval - randint1(11); + x2a = xval + randint1(10); + + /* Determine extents of the second room */ + y1b = yval - randint1(3); + y2b = yval + randint1(4); + x1b = xval - randint1(10); + x2b = xval + randint1(11); + + + /* Place a full floor for room "a" */ + for (y = y1a - 1; y <= y2a + 1; y++) + { + for (x = x1a - 1; x <= x2a + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Place a full floor for room "b" */ + for (y = y1b - 1; y <= y2b + 1; y++) + { + for (x = x1b - 1; x <= x2b + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + + /* Place the walls around room "a" */ + for (y = y1a - 1; y <= y2a + 1; y++) + { + c_ptr = &cave[y][x1a - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2a + 1]; + place_outer_grid(c_ptr); + } + for (x = x1a - 1; x <= x2a + 1; x++) + { + c_ptr = &cave[y1a - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2a + 1][x]; + place_outer_grid(c_ptr); + } + + /* Place the walls around room "b" */ + for (y = y1b - 1; y <= y2b + 1; y++) + { + c_ptr = &cave[y][x1b - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2b + 1]; + place_outer_grid(c_ptr); + } + for (x = x1b - 1; x <= x2b + 1; x++) + { + c_ptr = &cave[y1b - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2b + 1][x]; + place_outer_grid(c_ptr); + } + + + + /* Replace the floor for room "a" */ + for (y = y1a; y <= y2a; y++) + { + for (x = x1a; x <= x2a; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + } + } + + /* Replace the floor for room "b" */ + for (y = y1b; y <= y2b; y++) + { + for (x = x1b; x <= x2b; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + } + } + + return TRUE; +} + +/*! +* @brief タイプ3の部屋…十字型の部屋を生成する / Type 3 -- Cross shaped rooms +* @return なし +* @details +* Builds a room at a row, column coordinate\n +*\n +* Room "a" runs north/south, and Room "b" runs east/east\n +* So the "central pillar" runs from x1a, y1b to x2a, y2b.\n +*\n +* Note that currently, the "center" is always 3x3, but I think that\n +* the code below will work (with "bounds checking") for 5x5, or even\n +* for unsymetric values like 4x3 or 5x3 or 3x4 or 3x5, or even larger.\n +*/ +bool build_type3(void) +{ + POSITION y, x, dy, dx, wy, wx; + POSITION y1a, x1a, y2a, x2a; + POSITION y1b, x1b, y2b, x2b; + POSITION yval, xval; + bool light; + cave_type *c_ptr; + + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + /* For now, always 3x3 */ + wx = wy = 1; + + /* Pick max vertical size (at most 4) */ + dy = rand_range(3, 4); + + /* Pick max horizontal size (at most 15) */ + dx = rand_range(3, 11); + + + /* Determine extents of the north/south room */ + y1a = yval - dy; + y2a = yval + dy; + x1a = xval - wx; + x2a = xval + wx; + + /* Determine extents of the east/west room */ + y1b = yval - wy; + y2b = yval + wy; + x1b = xval - dx; + x2b = xval + dx; + + + /* Place a full floor for room "a" */ + for (y = y1a - 1; y <= y2a + 1; y++) + { + for (x = x1a - 1; x <= x2a + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Place a full floor for room "b" */ + for (y = y1b - 1; y <= y2b + 1; y++) + { + for (x = x1b - 1; x <= x2b + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + + /* Place the walls around room "a" */ + for (y = y1a - 1; y <= y2a + 1; y++) + { + c_ptr = &cave[y][x1a - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2a + 1]; + place_outer_grid(c_ptr); + } + for (x = x1a - 1; x <= x2a + 1; x++) + { + c_ptr = &cave[y1a - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2a + 1][x]; + place_outer_grid(c_ptr); + } + + /* Place the walls around room "b" */ + for (y = y1b - 1; y <= y2b + 1; y++) + { + c_ptr = &cave[y][x1b - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2b + 1]; + place_outer_grid(c_ptr); + } + for (x = x1b - 1; x <= x2b + 1; x++) + { + c_ptr = &cave[y1b - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2b + 1][x]; + place_outer_grid(c_ptr); + } + + + /* Replace the floor for room "a" */ + for (y = y1a; y <= y2a; y++) + { + for (x = x1a; x <= x2a; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + } + } + + /* Replace the floor for room "b" */ + for (y = y1b; y <= y2b; y++) + { + for (x = x1b; x <= x2b; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + } + } + + + + /* Special features (3/4) */ + switch (randint0(4)) + { + /* Large solid middle pillar */ + case 1: + { + for (y = y1b; y <= y2b; y++) + { + for (x = x1a; x <= x2a; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + break; + } + + /* Inner treasure vault */ + case 2: + { + /* Build the vault */ + for (y = y1b; y <= y2b; y++) + { + c_ptr = &cave[y][x1a]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2a]; + place_inner_grid(c_ptr); + } + for (x = x1a; x <= x2a; x++) + { + c_ptr = &cave[y1b][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2b][x]; + place_inner_grid(c_ptr); + } + + /* Place a secret door on the inner room */ + switch (randint0(4)) + { + case 0: place_secret_door(y1b, xval, DOOR_DEFAULT); break; + case 1: place_secret_door(y2b, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(yval, x1a, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x2a, DOOR_DEFAULT); break; + } + + /* Place a treasure in the vault */ + place_object(yval, xval, 0L); + + /* Let's guard the treasure well */ + vault_monsters(yval, xval, randint0(2) + 3); + + /* Traps naturally */ + vault_traps(yval, xval, 4, 4, randint0(3) + 2); + + break; + } + + /* Something else */ + case 3: + { + /* Occasionally pinch the center shut */ + if (one_in_(3)) + { + /* Pinch the east/west sides */ + for (y = y1b; y <= y2b; y++) + { + if (y == yval) continue; + c_ptr = &cave[y][x1a - 1]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2a + 1]; + place_inner_grid(c_ptr); + } + + /* Pinch the north/south sides */ + for (x = x1a; x <= x2a; x++) + { + if (x == xval) continue; + c_ptr = &cave[y1b - 1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2b + 1][x]; + place_inner_grid(c_ptr); + } + + /* Sometimes shut using secret doors */ + if (one_in_(3)) + { + int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && + one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : + ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); + + place_secret_door(yval, x1a - 1, door_type); + place_secret_door(yval, x2a + 1, door_type); + place_secret_door(y1b - 1, xval, door_type); + place_secret_door(y2b + 1, xval, door_type); + } + } + + /* Occasionally put a "plus" in the center */ + else if (one_in_(3)) + { + c_ptr = &cave[yval][xval]; + place_inner_grid(c_ptr); + c_ptr = &cave[y1b][xval]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2b][xval]; + place_inner_grid(c_ptr); + c_ptr = &cave[yval][x1a]; + place_inner_grid(c_ptr); + c_ptr = &cave[yval][x2a]; + place_inner_grid(c_ptr); + } + + /* Occasionally put a pillar in the center */ + else if (one_in_(3)) + { + c_ptr = &cave[yval][xval]; + place_inner_grid(c_ptr); + } + + break; + } + } + + return TRUE; +} + +/*! +* @brief タイプ4の部屋…固定サイズの二重構造部屋を生成する / Type 4 -- Large room with inner features +* @return なし +* @details +* Possible sub-types:\n +* 1 - Just an inner room with one door\n +* 2 - An inner room within an inner room\n +* 3 - An inner room with pillar(s)\n +* 4 - Inner room has a maze\n +* 5 - A set of four inner rooms\n +*/ +bool build_type4(void) +{ + POSITION y, x, y1, x1; + POSITION y2, x2, tmp, yval, xval; + bool light; + cave_type *c_ptr; + + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + /* Large room */ + y1 = yval - 4; + y2 = yval + 4; + x1 = xval - 11; + x2 = xval + 11; + + /* Place a full floor under the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Outer Walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + + /* The inner room */ + y1 = y1 + 2; + y2 = y2 - 2; + x1 = x1 + 2; + x2 = x2 - 2; + + /* The inner walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_inner_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_inner_grid(c_ptr); + } + + + /* Inner room variations */ + switch (randint1(5)) + { + /* Just an inner room with a monster */ + case 1: + { + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + /* Place a monster in the room */ + vault_monsters(yval, xval, 1); + + break; + } + + /* Treasure Vault (with a door) */ + case 2: + { + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + /* Place another inner room */ + for (y = yval - 1; y <= yval + 1; y++) + { + for (x = xval - 1; x <= xval + 1; x++) + { + if ((x == xval) && (y == yval)) continue; + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + + /* Place a locked door on the inner room */ + switch (randint1(4)) + { + case 1: place_locked_door(yval - 1, xval); break; + case 2: place_locked_door(yval + 1, xval); break; + case 3: place_locked_door(yval, xval - 1); break; + case 4: place_locked_door(yval, xval + 1); break; + } + + /* Monsters to guard the "treasure" */ + vault_monsters(yval, xval, randint1(3) + 2); + + /* Object (80%) */ + if (randint0(100) < 80) + { + place_object(yval, xval, 0L); + } + + /* Stairs (20%) */ + else + { + place_random_stairs(yval, xval); + } + + /* Traps to protect the treasure */ + vault_traps(yval, xval, 4, 10, 2 + randint1(3)); + + break; + } + + /* Inner pillar(s). */ + case 3: + { + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + /* Large Inner Pillar */ + for (y = yval - 1; y <= yval + 1; y++) + { + for (x = xval - 1; x <= xval + 1; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + + /* Occasionally, two more Large Inner Pillars */ + if (one_in_(2)) + { + tmp = randint1(2); + for (y = yval - 1; y <= yval + 1; y++) + { + for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + } + + /* Occasionally, some Inner rooms */ + if (one_in_(3)) + { + int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && + one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : + ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); + + /* Long horizontal walls */ + for (x = xval - 5; x <= xval + 5; x++) + { + c_ptr = &cave[yval - 1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[yval + 1][x]; + place_inner_grid(c_ptr); + } + + /* Close off the left/right edges */ + c_ptr = &cave[yval][xval - 5]; + place_inner_grid(c_ptr); + c_ptr = &cave[yval][xval + 5]; + place_inner_grid(c_ptr); + + /* Secret doors (random top/bottom) */ + place_secret_door(yval - 3 + (randint1(2) * 2), xval - 3, door_type); + place_secret_door(yval - 3 + (randint1(2) * 2), xval + 3, door_type); + + /* Monsters */ + vault_monsters(yval, xval - 2, randint1(2)); + vault_monsters(yval, xval + 2, randint1(2)); + + /* Objects */ + if (one_in_(3)) place_object(yval, xval - 2, 0L); + if (one_in_(3)) place_object(yval, xval + 2, 0L); + } + + break; + } + + /* Maze inside. */ + case 4: + { + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + /* Maze (really a checkerboard) */ + for (y = y1; y <= y2; y++) + { + for (x = x1; x <= x2; x++) + { + if (0x1 & (x + y)) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + } + } + } + + /* Monsters just love mazes. */ + vault_monsters(yval, xval - 5, randint1(3)); + vault_monsters(yval, xval + 5, randint1(3)); + + /* Traps make them entertaining. */ + vault_traps(yval, xval - 3, 2, 8, randint1(3)); + vault_traps(yval, xval + 3, 2, 8, randint1(3)); + + /* Mazes should have some treasure too. */ + vault_objects(yval, xval, 3); + + break; + } + + /* Four small rooms. */ + case 5: + { + int door_type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && + one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : + ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); + + /* Inner "cross" */ + for (y = y1; y <= y2; y++) + { + c_ptr = &cave[y][xval]; + place_inner_grid(c_ptr); + } + for (x = x1; x <= x2; x++) + { + c_ptr = &cave[yval][x]; + place_inner_grid(c_ptr); + } + + /* Doors into the rooms */ + if (randint0(100) < 50) + { + int i = randint1(10); + place_secret_door(y1 - 1, xval - i, door_type); + place_secret_door(y1 - 1, xval + i, door_type); + place_secret_door(y2 + 1, xval - i, door_type); + place_secret_door(y2 + 1, xval + i, door_type); + } + else + { + int i = randint1(3); + place_secret_door(yval + i, x1 - 1, door_type); + place_secret_door(yval - i, x1 - 1, door_type); + place_secret_door(yval + i, x2 + 1, door_type); + place_secret_door(yval - i, x2 + 1, door_type); + } + + /* Treasure, centered at the center of the cross */ + vault_objects(yval, xval, 2 + randint1(2)); + + /* Gotta have some monsters. */ + vault_monsters(yval + 1, xval - 4, randint1(4)); + vault_monsters(yval + 1, xval + 4, randint1(4)); + vault_monsters(yval - 1, xval - 4, randint1(4)); + vault_monsters(yval - 1, xval + 4, randint1(4)); + + break; + } + } + + return TRUE; +} + + +/*! +* @brief タイプ11の部屋…円形部屋の生成 / Type 11 -- Build an vertical oval room. +* @return なし +* @details +* For every grid in the possible square, check the distance.\n +* If it's less than the radius, make it a room square.\n +*\n +* When done fill from the inside to find the walls,\n +*/ +bool build_type11(void) +{ + POSITION rad, x, y, x0, y0; + int light = FALSE; + + /* Occasional light */ + if ((randint1(dun_level) <= 15) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; + + rad = randint0(9); + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, rad * 2 + 1, rad * 2 + 1)) return FALSE; + + /* Make circular floor */ + for (x = x0 - rad; x <= x0 + rad; x++) + { + for (y = y0 - rad; y <= y0 + rad; y++) + { + if (distance(y0, x0, y, x) <= rad - 1) + { + /* inside- so is floor */ + place_floor_bold(y, x); + } + else if (distance(y0, x0, y, x) <= rad + 1) + { + /* make granite outside so arena works */ + place_extra_bold(y, x); + } + } + } + + /* Find visible outer walls and set to be FEAT_OUTER */ + add_outer_wall(x0, y0, light, x0 - rad, y0 - rad, x0 + rad, y0 + rad); + + return TRUE; +} + + +/*! +* @brief タイプ12の部屋…ドーム型部屋の生成 / Type 12 -- Build crypt room. +* @return なし +* @details +* For every grid in the possible square, check the (fake) distance.\n +* If it's less than the radius, make it a room square.\n +*\n +* When done fill from the inside to find the walls,\n +*/ +bool build_type12(void) +{ + POSITION rad, x, y, x0, y0; + int light = FALSE; + bool emptyflag = TRUE; + + /* Make a random metric */ + POSITION h1, h2, h3, h4; + h1 = randint1(32) - 16; + h2 = randint1(16); + h3 = randint1(32); + h4 = randint1(32) - 16; + + /* Occasional light */ + if ((randint1(dun_level) <= 5) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) light = TRUE; + + rad = randint1(9); + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, rad * 2 + 3, rad * 2 + 3)) return FALSE; + + /* Make floor */ + for (x = x0 - rad; x <= x0 + rad; x++) + { + for (y = y0 - rad; y <= y0 + rad; y++) + { + /* clear room flag */ + cave[y][x].info &= ~(CAVE_ROOM); + + if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) + { + /* inside - so is floor */ + place_floor_bold(y, x); + } + else if (distance(y0, x0, y, x) < 3) + { + place_floor_bold(y, x); + } + else + { + /* make granite outside so arena works */ + place_extra_bold(y, x); + } + + /* proper boundary for arena */ + if (((y + rad) == y0) || ((y - rad) == y0) || + ((x + rad) == x0) || ((x - rad) == x0)) + { + place_extra_bold(y, x); + } + } + } + + /* Find visible outer walls and set to be FEAT_OUTER */ + add_outer_wall(x0, y0, light, x0 - rad - 1, y0 - rad - 1, + x0 + rad + 1, y0 + rad + 1); + + /* Check to see if there is room for an inner vault */ + for (x = x0 - 2; x <= x0 + 2; x++) + { + for (y = y0 - 2; y <= y0 + 2; y++) + { + if (!is_floor_bold(y, x)) + { + /* Wall in the way */ + emptyflag = FALSE; + } + } + } + + if (emptyflag && one_in_(2)) + { + /* Build the vault */ + build_small_room(x0, y0); + + /* Place a treasure in the vault */ + place_object(y0, x0, 0L); + + /* Let's guard the treasure well */ + vault_monsters(y0, x0, randint0(2) + 3); + + /* Traps naturally */ + vault_traps(y0, x0, 4, 4, randint0(3) + 2); + } + + return TRUE; +} + diff --git a/src/rooms-normal.h b/src/rooms-normal.h index c7569b221..cd2b06595 100644 --- a/src/rooms-normal.h +++ b/src/rooms-normal.h @@ -1,6 +1,6 @@ -extern bool build_type1(void); -extern bool build_type2(void); -extern bool build_type3(void); -extern bool build_type4(void); -extern bool build_type11(void); -extern bool build_type12(void); +extern bool build_type1(void); +extern bool build_type2(void); +extern bool build_type3(void); +extern bool build_type4(void); +extern bool build_type11(void); +extern bool build_type12(void); diff --git a/src/rooms-pitnest.c b/src/rooms-pitnest.c index c12a9b97e..cd3dfa749 100644 --- a/src/rooms-pitnest.c +++ b/src/rooms-pitnest.c @@ -1,1001 +1,1001 @@ -#include "angband.h" -#include "grid.h" -#include "generate.h" -#include "rooms.h" -#include "rooms-pitnest.h" -#include "monster.h" -#include "monsterrace-hook.h" -#include "sort.h" - - - -#define NUM_NEST_MON_TYPE 64 /*!name) break; - - /* Ignore excessive depth */ - if (n_ptr->level > dun_level) continue; - - /* Not matched with pit/nest flag */ - if (!(allow_flag_mask & (1L << count))) continue; - - /* Count this possibility */ - total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); - } - - /* Pick a random type */ - tmp = randint0(total); - - /* Find this type */ - for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++) - { - /* Note end */ - if (!n_ptr->name) break; - - /* Ignore excessive depth */ - if (n_ptr->level > dun_level) continue; - - /* Not matched with pit/nest flag */ - if (!(allow_flag_mask & (1L << count))) continue; - - /* Count this possibility */ - total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); - - /* Found the type */ - if (tmp < total) break; - } - - return n_ptr->name ? count : -1; -} - -/*! -* @brief デバッグ時に生成されたpit/nestの型を出力する処理 -* @param type pit/nestの型ID -* @param nest TRUEならばnest、FALSEならばpit -* @return デバッグ表示文字列の参照ポインタ -* @details -* Hack -- Get the string describing subtype of pit/nest -* Determined in prepare function (some pit/nest only) -*/ -static concptr pit_subtype_string(int type, bool nest) -{ - static char inner_buf[256] = ""; - - inner_buf[0] = '\0'; /* Init string */ - - if (nest) /* Nests */ - { - switch (type) - { - case NEST_TYPE_CLONE: - sprintf(inner_buf, "(%s)", r_name + r_info[vault_aux_race].name); - break; - case NEST_TYPE_SYMBOL_GOOD: - case NEST_TYPE_SYMBOL_EVIL: - sprintf(inner_buf, "(%c)", vault_aux_char); - break; - } - } - else /* Pits */ - { - switch (type) - { - case PIT_TYPE_SYMBOL_GOOD: - case PIT_TYPE_SYMBOL_EVIL: - sprintf(inner_buf, "(%c)", vault_aux_char); - break; - case PIT_TYPE_DRAGON: - switch (vault_aux_dragon_mask4) - { - case RF4_BR_ACID: strcpy(inner_buf, _("(酸)", "(acid)")); break; - case RF4_BR_ELEC: strcpy(inner_buf, _("(稲妻)", "(lightning)")); break; - case RF4_BR_FIRE: strcpy(inner_buf, _("(火炎)", "(fire)")); break; - case RF4_BR_COLD: strcpy(inner_buf, _("(冷気)", "(frost)")); break; - case RF4_BR_POIS: strcpy(inner_buf, _("(毒)", "(poison)")); break; - case (RF4_BR_ACID | RF4_BR_ELEC | RF4_BR_FIRE | RF4_BR_COLD | RF4_BR_POIS) : - strcpy(inner_buf, _("(万色)", "(multi-hued)")); break; - default: strcpy(inner_buf, _("(未定義)", "(undefined)")); break; - } - break; - } - } - - return inner_buf; -} - -/* -*! @brief nestのモンスターリストをソートするための関数 / -* Comp function for sorting nest monster information -* @param u ソート処理対象配列ポインタ -* @param v 未使用 -* @param a 比較対象参照ID1 -* @param b 比較対象参照ID2 -*/ -static bool ang_sort_comp_nest_mon_info(vptr u, vptr v, int a, int b) -{ - nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; - MONSTER_IDX w1 = nest_mon_info[a].r_idx; - MONSTER_IDX w2 = nest_mon_info[b].r_idx; - monster_race *r1_ptr = &r_info[w1]; - monster_race *r2_ptr = &r_info[w2]; - int z1, z2; - - /* Unused */ - (void)v; - - /* Extract used info */ - z1 = nest_mon_info[a].used; - z2 = nest_mon_info[b].used; - - /* Compare used status */ - if (z1 < z2) return FALSE; - if (z1 > z2) return TRUE; - - /* Compare levels */ - if (r1_ptr->level < r2_ptr->level) return TRUE; - if (r1_ptr->level > r2_ptr->level) return FALSE; - - /* Compare experience */ - if (r1_ptr->mexp < r2_ptr->mexp) return TRUE; - if (r1_ptr->mexp > r2_ptr->mexp) return FALSE; - - /* Compare indexes */ - return w1 <= w2; -} - -/*! -* @brief nestのモンスターリストをスワップするための関数 / -* Swap function for sorting nest monster information -* @param u スワップ処理対象配列ポインタ -* @param v 未使用 -* @param a スワップ対象参照ID1 -* @param b スワップ対象参照ID2 -*/ -static void ang_sort_swap_nest_mon_info(vptr u, vptr v, int a, int b) -{ - nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; - nest_mon_info_type holder; - - /* Unused */ - (void)v; - - /* Swap */ - holder = nest_mon_info[a]; - nest_mon_info[a] = nest_mon_info[b]; - nest_mon_info[b] = holder; -} - - - -/*!nest情報テーブル*/ -static vault_aux_type nest_types[] = -{ - { _("クローン", "clone"), vault_aux_clone, vault_prep_clone, 5, 3 }, - { _("ゼリー", "jelly"), vault_aux_jelly, NULL, 5, 6 }, - { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 }, - { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 }, - { _("ミミック", "mimic"), vault_aux_mimic, NULL, 30, 4 }, - { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 70, 2 }, - { _("犬小屋", "kennel"), vault_aux_kennel, NULL, 45, 4 }, - { _("動物園", "animal"), vault_aux_animal, NULL, 35, 5 }, - { _("教会", "chapel"), vault_aux_chapel_g, NULL, 75, 4 }, - { _("アンデッド", "undead"), vault_aux_undead, NULL, 75, 5 }, - { NULL, NULL, NULL, 0, 0 }, -}; - -/*!pit情報テーブル*/ -static vault_aux_type pit_types[] = -{ - { _("オーク", "orc"), vault_aux_orc, NULL, 5, 6 }, - { _("トロル", "troll"), vault_aux_troll, NULL, 20, 6 }, - { _("ジャイアント", "giant"), vault_aux_giant, NULL, 50, 6 }, - { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 80, 2 }, - { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 }, - { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 }, - { _("教会", "chapel"), vault_aux_chapel_g, NULL, 65, 2 }, - { _("ドラゴン", "dragon"), vault_aux_dragon, vault_prep_dragon, 70, 6 }, - { _("デーモン", "demon"), vault_aux_demon, NULL, 80, 6 }, - { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL, 45, 4 }, - { NULL, NULL, NULL, 0, 0 }, -}; - - - - -/*! -* @brief タイプ5の部屋…nestを生成する / Type 5 -- Monster nests -* @return なし -* @details -* A monster nest is a "big" room, with an "inner" room, containing\n -* a "collection" of monsters of a given type strewn about the room.\n -*\n -* The monsters are chosen from a set of 64 randomly selected monster\n -* races, to allow the nest creation to fail instead of having "holes".\n -*\n -* Note the use of the "get_mon_num_prep()" function, and the special\n -* "get_mon_num_hook()" restriction function, to prepare the "monster\n -* allocation table" in such a way as to optimize the selection of\n -* "appropriate" non-unique monsters for the nest.\n -*\n -* Note that the "get_mon_num()" function may (rarely) fail, in which\n -* case the nest will be empty.\n -*\n -* Note that "monster nests" will never contain "unique" monsters.\n -*/ -bool build_type5(void) -{ - POSITION y, x, y1, x1, y2, x2, xval, yval; - int i; - nest_mon_info_type nest_mon_info[NUM_NEST_MON_TYPE]; - - monster_type align; - - cave_type *c_ptr; - - int cur_nest_type = pick_vault_type(nest_types, d_info[p_ptr->dungeon_idx].nest); - vault_aux_type *n_ptr; - - /* No type available */ - if (cur_nest_type < 0) return FALSE; - - n_ptr = &nest_types[cur_nest_type]; - - /* Process a preparation function if necessary */ - if (n_ptr->prep_func) (*(n_ptr->prep_func))(); - get_mon_num_prep(n_ptr->hook_func, NULL); - - align.sub_align = SUB_ALIGN_NEUTRAL; - - /* Pick some monster types */ - for (i = 0; i < NUM_NEST_MON_TYPE; i++) - { - MONRACE_IDX r_idx = 0; - int attempts = 100; - monster_race *r_ptr = NULL; - - while (attempts--) - { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 11); - r_ptr = &r_info[r_idx]; - - /* Decline incorrect alignment */ - if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; - - /* Accept this monster */ - break; - } - - /* Notice failure */ - if (!r_idx || !attempts) return FALSE; - - /* Note the alignment */ - if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; - if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; - - nest_mon_info[i].r_idx = (s16b)r_idx; - nest_mon_info[i].used = FALSE; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 11, 25)) return FALSE; - - /* Large room */ - y1 = yval - 4; - y2 = yval + 4; - x1 = xval - 11; - x2 = xval + 11; - - /* Place the floor area */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - } - } - - /* Place the outer walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - - /* Advance to the center room */ - y1 = y1 + 2; - y2 = y2 - 2; - x1 = x1 + 2; - x2 = x2 - 2; - - /* The inner walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_inner_grid(c_ptr); - } - - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_inner_grid(c_ptr); - } - for (y = y1; y <= y2; y++) - { - for (x = x1; x <= x2; x++) - { - add_cave_info(y, x, CAVE_ICKY); - } - } - - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, TRUE)); - - /* Place some monsters */ - for (y = yval - 2; y <= yval + 2; y++) - { - for (x = xval - 9; x <= xval + 9; x++) - { - MONRACE_IDX r_idx; - - i = randint0(NUM_NEST_MON_TYPE); - r_idx = nest_mon_info[i].r_idx; - - /* Place that "random" monster (no groups) */ - (void)place_monster_aux(0, y, x, r_idx, 0L); - - nest_mon_info[i].used = TRUE; - } - } - - if (cheat_room) - { - ang_sort_comp = ang_sort_comp_nest_mon_info; - ang_sort_swap = ang_sort_swap_nest_mon_info; - ang_sort(nest_mon_info, NULL, NUM_NEST_MON_TYPE); - - /* Dump the entries (prevent multi-printing) */ - for (i = 0; i < NUM_NEST_MON_TYPE; i++) - { - if (!nest_mon_info[i].used) break; - for (; i < NUM_NEST_MON_TYPE - 1; i++) - { - if (nest_mon_info[i].r_idx != nest_mon_info[i + 1].r_idx) break; - if (!nest_mon_info[i + 1].used) break; - } - msg_format_wizard(CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, r_name + r_info[nest_mon_info[i].r_idx].name); - } - } - - return TRUE; -} - - -/*! -* @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits -* @return なし -* @details -* A monster pit is a "big" room, with an "inner" room, containing\n -* a "collection" of monsters of a given type organized in the room.\n -*\n -* The inside room in a monster pit appears as shown below, where the\n -* actual monsters in each location depend on the type of the pit\n -*\n -* XXXXXXXXXXXXXXXXXXXXX\n -* X0000000000000000000X\n -* X0112233455543322110X\n -* X0112233467643322110X\n -* X0112233455543322110X\n -* X0000000000000000000X\n -* XXXXXXXXXXXXXXXXXXXXX\n -*\n -* Note that the monsters in the pit are now chosen by using "get_mon_num()"\n -* to request 16 "appropriate" monsters, sorting them by level, and using\n -* the "even" entries in this sorted list for the contents of the pit.\n -*\n -* Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n -* which is handled by requiring a specific "breath" attack for all of the\n -* dragons. This may include "multi-hued" breath. Note that "wyrms" may\n -* be present in many of the dragon pits, if they have the proper breath.\n -*\n -* Note the use of the "get_mon_num_prep()" function, and the special\n -* "get_mon_num_hook()" restriction function, to prepare the "monster\n -* allocation table" in such a way as to optimize the selection of\n -* "appropriate" non-unique monsters for the pit.\n -*\n -* Note that the "get_mon_num()" function may (rarely) fail, in which case\n -* the pit will be empty.\n -*\n -* Note that "monster pits" will never contain "unique" monsters.\n -*/ -bool build_type6(void) -{ - POSITION y, x, y1, x1, y2, x2, xval, yval; - int i, j; - - MONRACE_IDX what[16]; - - monster_type align; - - cave_type *c_ptr; - - int cur_pit_type = pick_vault_type(pit_types, d_info[p_ptr->dungeon_idx].pit); - vault_aux_type *n_ptr; - - /* No type available */ - if (cur_pit_type < 0) return FALSE; - - n_ptr = &pit_types[cur_pit_type]; - - /* Process a preparation function if necessary */ - if (n_ptr->prep_func) (*(n_ptr->prep_func))(); - get_mon_num_prep(n_ptr->hook_func, NULL); - - align.sub_align = SUB_ALIGN_NEUTRAL; - - /* Pick some monster types */ - for (i = 0; i < 16; i++) - { - MONRACE_IDX r_idx = 0; - int attempts = 100; - monster_race *r_ptr = NULL; - - while (attempts--) - { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 11); - r_ptr = &r_info[r_idx]; - - /* Decline incorrect alignment */ - if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; - - /* Accept this monster */ - break; - } - - /* Notice failure */ - if (!r_idx || !attempts) return FALSE; - - /* Note the alignment */ - if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; - if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; - - what[i] = r_idx; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 11, 25)) return FALSE; - - /* Large room */ - y1 = yval - 4; - y2 = yval + 4; - x1 = xval - 11; - x2 = xval + 11; - - /* Place the floor area */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - } - } - - /* Place the outer walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - /* Advance to the center room */ - y1 = y1 + 2; - y2 = y2 - 2; - x1 = x1 + 2; - x2 = x2 - 2; - - /* The inner walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_inner_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_inner_grid(c_ptr); - } - for (y = y1; y <= y2; y++) - { - for (x = x1; x <= x2; x++) - { - add_cave_info(y, x, CAVE_ICKY); - } - } - - /* Place a secret door */ - switch (randint1(4)) - { - case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; - case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; - case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; - case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; - } - - /* Sort the entries */ - for (i = 0; i < 16 - 1; i++) - { - /* Sort the entries */ - for (j = 0; j < 16 - 1; j++) - { - int i1 = j; - int i2 = j + 1; - - int p1 = r_info[what[i1]].level; - int p2 = r_info[what[i2]].level; - - /* Bubble */ - if (p1 > p2) - { - MONRACE_IDX tmp = what[i1]; - what[i1] = what[i2]; - what[i2] = tmp; - } - } - } - - msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); - - /* Select the entries */ - for (i = 0; i < 8; i++) - { - /* Every other entry */ - what[i] = what[i * 2]; - msg_format_wizard(CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_name + r_info[what[i]].name); - } - - /* Top and bottom rows */ - for (x = xval - 9; x <= xval + 9; x++) - { - place_monster_aux(0, yval - 2, x, what[0], PM_NO_KAGE); - place_monster_aux(0, yval + 2, x, what[0], PM_NO_KAGE); - } - - /* Middle columns */ - for (y = yval - 1; y <= yval + 1; y++) - { - place_monster_aux(0, y, xval - 9, what[0], PM_NO_KAGE); - place_monster_aux(0, y, xval + 9, what[0], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 8, what[1], PM_NO_KAGE); - place_monster_aux(0, y, xval + 8, what[1], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 7, what[1], PM_NO_KAGE); - place_monster_aux(0, y, xval + 7, what[1], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 6, what[2], PM_NO_KAGE); - place_monster_aux(0, y, xval + 6, what[2], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 5, what[2], PM_NO_KAGE); - place_monster_aux(0, y, xval + 5, what[2], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 4, what[3], PM_NO_KAGE); - place_monster_aux(0, y, xval + 4, what[3], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 3, what[3], PM_NO_KAGE); - place_monster_aux(0, y, xval + 3, what[3], PM_NO_KAGE); - - place_monster_aux(0, y, xval - 2, what[4], PM_NO_KAGE); - place_monster_aux(0, y, xval + 2, what[4], PM_NO_KAGE); - } - - /* Above/Below the center monster */ - for (x = xval - 1; x <= xval + 1; x++) - { - place_monster_aux(0, yval + 1, x, what[5], PM_NO_KAGE); - place_monster_aux(0, yval - 1, x, what[5], PM_NO_KAGE); - } - - /* Next to the center monster */ - place_monster_aux(0, yval, xval + 1, what[6], PM_NO_KAGE); - place_monster_aux(0, yval, xval - 1, what[6], PM_NO_KAGE); - - /* Center monster */ - place_monster_aux(0, yval, xval, what[7], PM_NO_KAGE); - - return TRUE; -} - - - -/* -* Helper function for "trapped monster pit" -*/ -static bool vault_aux_trapped_pit(MONRACE_IDX r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - if (!vault_monster_okay(r_idx)) return (FALSE); - - /* No wall passing monster */ - if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE); - - return (TRUE); -} - - -/*! -* @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits -* @return なし -* @details -* A trapped monster pit is a "big" room with a straight corridor in\n -* which wall opening traps are placed, and with two "inner" rooms\n -* containing a "collection" of monsters of a given type organized in\n -* the room.\n -*\n -* The trapped monster pit appears as shown below, where the actual\n -* monsters in each location depend on the type of the pit\n -*\n -* XXXXXXXXXXXXXXXXXXXXXXXXX\n -* X X\n -* XXXXXXXXXXXXXXXXXXXXXXX X\n -* XXXXX001123454321100XXX X\n -* XXX0012234567654322100X X\n -* XXXXXXXXXXXXXXXXXXXXXXX X\n -* X ^ X\n -* X XXXXXXXXXXXXXXXXXXXXXXX\n -* X X0012234567654322100XXX\n -* X XXX001123454321100XXXXX\n -* X XXXXXXXXXXXXXXXXXXXXXXX\n -* X X\n -* XXXXXXXXXXXXXXXXXXXXXXXXX\n -*\n -* Note that the monsters in the pit are now chosen by using "get_mon_num()"\n -* to request 16 "appropriate" monsters, sorting them by level, and using\n -* the "even" entries in this sorted list for the contents of the pit.\n -*\n -* Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n -* which is handled by requiring a specific "breath" attack for all of the\n -* dragons. This may include "multi-hued" breath. Note that "wyrms" may\n -* be present in many of the dragon pits, if they have the proper breath.\n -*\n -* Note the use of the "get_mon_num_prep()" function, and the special\n -* "get_mon_num_hook()" restriction function, to prepare the "monster\n -* allocation table" in such a way as to optimize the selection of\n -* "appropriate" non-unique monsters for the pit.\n -*\n -* Note that the "get_mon_num()" function may (rarely) fail, in which case\n -* the pit will be empty.\n -*\n -* Note that "monster pits" will never contain "unique" monsters.\n -*/ -bool build_type13(void) -{ - static int placing[][3] = { - { -2, -9, 0 },{ -2, -8, 0 },{ -3, -7, 0 },{ -3, -6, 0 }, - { +2, -9, 0 },{ +2, -8, 0 },{ +3, -7, 0 },{ +3, -6, 0 }, - { -2, +9, 0 },{ -2, +8, 0 },{ -3, +7, 0 },{ -3, +6, 0 }, - { +2, +9, 0 },{ +2, +8, 0 },{ +3, +7, 0 },{ +3, +6, 0 }, - { -2, -7, 1 },{ -3, -5, 1 },{ -3, -4, 1 }, - { +2, -7, 1 },{ +3, -5, 1 },{ +3, -4, 1 }, - { -2, +7, 1 },{ -3, +5, 1 },{ -3, +4, 1 }, - { +2, +7, 1 },{ +3, +5, 1 },{ +3, +4, 1 }, - { -2, -6, 2 },{ -2, -5, 2 },{ -3, -3, 2 }, - { +2, -6, 2 },{ +2, -5, 2 },{ +3, -3, 2 }, - { -2, +6, 2 },{ -2, +5, 2 },{ -3, +3, 2 }, - { +2, +6, 2 },{ +2, +5, 2 },{ +3, +3, 2 }, - { -2, -4, 3 },{ -3, -2, 3 }, - { +2, -4, 3 },{ +3, -2, 3 }, - { -2, +4, 3 },{ -3, +2, 3 }, - { +2, +4, 3 },{ +3, +2, 3 }, - { -2, -3, 4 },{ -3, -1, 4 }, - { +2, -3, 4 },{ +3, -1, 4 }, - { -2, +3, 4 },{ -3, +1, 4 }, - { +2, +3, 4 },{ +3, +1, 4 }, - { -2, -2, 5 },{ -3, 0, 5 },{ -2, +2, 5 }, - { +2, -2, 5 },{ +3, 0, 5 },{ +2, +2, 5 }, - { -2, -1, 6 },{ -2, +1, 6 }, - { +2, -1, 6 },{ +2, +1, 6 }, - { -2, 0, 7 },{ +2, 0, 7 }, - { 0, 0, -1 } - }; - - POSITION y, x, y1, x1, y2, x2, xval, yval; - int i, j; - - MONRACE_IDX what[16]; - - monster_type align; - - cave_type *c_ptr; - - int cur_pit_type = pick_vault_type(pit_types, d_info[p_ptr->dungeon_idx].pit); - vault_aux_type *n_ptr; - - /* Only in Angband */ - if (p_ptr->dungeon_idx != DUNGEON_ANGBAND) return FALSE; - - /* No type available */ - if (cur_pit_type < 0) return FALSE; - - n_ptr = &pit_types[cur_pit_type]; - - /* Process a preparation function if necessary */ - if (n_ptr->prep_func) (*(n_ptr->prep_func))(); - get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit); - - align.sub_align = SUB_ALIGN_NEUTRAL; - - /* Pick some monster types */ - for (i = 0; i < 16; i++) - { - MONRACE_IDX r_idx = 0; - int attempts = 100; - monster_race *r_ptr = NULL; - - while (attempts--) - { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 0); - r_ptr = &r_info[r_idx]; - - /* Decline incorrect alignment */ - if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; - - /* Accept this monster */ - break; - } - - /* Notice failure */ - if (!r_idx || !attempts) return FALSE; - - /* Note the alignment */ - if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; - if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; - - what[i] = r_idx; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, 13, 25)) return FALSE; - - /* Large room */ - y1 = yval - 5; - y2 = yval + 5; - x1 = xval - 11; - x2 = xval + 11; - - /* Fill with inner walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - } - } - - /* Place the floor area 1 */ - for (x = x1 + 3; x <= x2 - 3; x++) - { - c_ptr = &cave[yval - 2][x]; - place_floor_grid(c_ptr); - add_cave_info(yval - 2, x, CAVE_ICKY); - - c_ptr = &cave[yval + 2][x]; - place_floor_grid(c_ptr); - add_cave_info(yval + 2, x, CAVE_ICKY); - } - - /* Place the floor area 2 */ - for (x = x1 + 5; x <= x2 - 5; x++) - { - c_ptr = &cave[yval - 3][x]; - place_floor_grid(c_ptr); - add_cave_info(yval - 3, x, CAVE_ICKY); - - c_ptr = &cave[yval + 3][x]; - place_floor_grid(c_ptr); - add_cave_info(yval + 3, x, CAVE_ICKY); - } - - /* Corridor */ - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[yval][x]; - place_floor_grid(c_ptr); - c_ptr = &cave[y1][x]; - place_floor_grid(c_ptr); - c_ptr = &cave[y2][x]; - place_floor_grid(c_ptr); - } - - /* Place the outer walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - /* Random corridor */ - if (one_in_(2)) - { - for (y = y1; y <= yval; y++) - { - place_floor_bold(y, x2); - place_solid_bold(y, x1 - 1); - } - for (y = yval; y <= y2 + 1; y++) - { - place_floor_bold(y, x1); - place_solid_bold(y, x2 + 1); - } - } - else - { - for (y = yval; y <= y2 + 1; y++) - { - place_floor_bold(y, x1); - place_solid_bold(y, x2 + 1); - } - for (y = y1; y <= yval; y++) - { - place_floor_bold(y, x2); - place_solid_bold(y, x1 - 1); - } - } - - /* Place the wall open trap */ - cave[yval][xval].mimic = cave[yval][xval].feat; - cave[yval][xval].feat = feat_trap_open; - - /* Sort the entries */ - for (i = 0; i < 16 - 1; i++) - { - /* Sort the entries */ - for (j = 0; j < 16 - 1; j++) - { - int i1 = j; - int i2 = j + 1; - - int p1 = r_info[what[i1]].level; - int p2 = r_info[what[i2]].level; - - /* Bubble */ - if (p1 > p2) - { - MONRACE_IDX tmp = what[i1]; - what[i1] = what[i2]; - what[i2] = tmp; - } - } - } - - msg_format_wizard(CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), - n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); - - /* Select the entries */ - for (i = 0; i < 8; i++) - { - /* Every other entry */ - what[i] = what[i * 2]; - - if (cheat_hear) - { - msg_print(r_name + r_info[what[i]].name); - } - } - - for (i = 0; placing[i][2] >= 0; i++) - { - y = yval + placing[i][0]; - x = xval + placing[i][1]; - place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE); - } - - return TRUE; -} - +#include "angband.h" +#include "grid.h" +#include "generate.h" +#include "rooms.h" +#include "rooms-pitnest.h" +#include "monster.h" +#include "monsterrace-hook.h" +#include "sort.h" + + + +#define NUM_NEST_MON_TYPE 64 /*!name) break; + + /* Ignore excessive depth */ + if (n_ptr->level > dun_level) continue; + + /* Not matched with pit/nest flag */ + if (!(allow_flag_mask & (1L << count))) continue; + + /* Count this possibility */ + total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); + } + + /* Pick a random type */ + tmp = randint0(total); + + /* Find this type */ + for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++) + { + /* Note end */ + if (!n_ptr->name) break; + + /* Ignore excessive depth */ + if (n_ptr->level > dun_level) continue; + + /* Not matched with pit/nest flag */ + if (!(allow_flag_mask & (1L << count))) continue; + + /* Count this possibility */ + total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); + + /* Found the type */ + if (tmp < total) break; + } + + return n_ptr->name ? count : -1; +} + +/*! +* @brief デバッグ時に生成されたpit/nestの型を出力する処理 +* @param type pit/nestの型ID +* @param nest TRUEならばnest、FALSEならばpit +* @return デバッグ表示文字列の参照ポインタ +* @details +* Hack -- Get the string describing subtype of pit/nest +* Determined in prepare function (some pit/nest only) +*/ +static concptr pit_subtype_string(int type, bool nest) +{ + static char inner_buf[256] = ""; + + inner_buf[0] = '\0'; /* Init string */ + + if (nest) /* Nests */ + { + switch (type) + { + case NEST_TYPE_CLONE: + sprintf(inner_buf, "(%s)", r_name + r_info[vault_aux_race].name); + break; + case NEST_TYPE_SYMBOL_GOOD: + case NEST_TYPE_SYMBOL_EVIL: + sprintf(inner_buf, "(%c)", vault_aux_char); + break; + } + } + else /* Pits */ + { + switch (type) + { + case PIT_TYPE_SYMBOL_GOOD: + case PIT_TYPE_SYMBOL_EVIL: + sprintf(inner_buf, "(%c)", vault_aux_char); + break; + case PIT_TYPE_DRAGON: + switch (vault_aux_dragon_mask4) + { + case RF4_BR_ACID: strcpy(inner_buf, _("(酸)", "(acid)")); break; + case RF4_BR_ELEC: strcpy(inner_buf, _("(稲妻)", "(lightning)")); break; + case RF4_BR_FIRE: strcpy(inner_buf, _("(火炎)", "(fire)")); break; + case RF4_BR_COLD: strcpy(inner_buf, _("(冷気)", "(frost)")); break; + case RF4_BR_POIS: strcpy(inner_buf, _("(毒)", "(poison)")); break; + case (RF4_BR_ACID | RF4_BR_ELEC | RF4_BR_FIRE | RF4_BR_COLD | RF4_BR_POIS) : + strcpy(inner_buf, _("(万色)", "(multi-hued)")); break; + default: strcpy(inner_buf, _("(未定義)", "(undefined)")); break; + } + break; + } + } + + return inner_buf; +} + +/* +*! @brief nestのモンスターリストをソートするための関数 / +* Comp function for sorting nest monster information +* @param u ソート処理対象配列ポインタ +* @param v 未使用 +* @param a 比較対象参照ID1 +* @param b 比較対象参照ID2 +*/ +static bool ang_sort_comp_nest_mon_info(vptr u, vptr v, int a, int b) +{ + nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; + MONSTER_IDX w1 = nest_mon_info[a].r_idx; + MONSTER_IDX w2 = nest_mon_info[b].r_idx; + monster_race *r1_ptr = &r_info[w1]; + monster_race *r2_ptr = &r_info[w2]; + int z1, z2; + + /* Unused */ + (void)v; + + /* Extract used info */ + z1 = nest_mon_info[a].used; + z2 = nest_mon_info[b].used; + + /* Compare used status */ + if (z1 < z2) return FALSE; + if (z1 > z2) return TRUE; + + /* Compare levels */ + if (r1_ptr->level < r2_ptr->level) return TRUE; + if (r1_ptr->level > r2_ptr->level) return FALSE; + + /* Compare experience */ + if (r1_ptr->mexp < r2_ptr->mexp) return TRUE; + if (r1_ptr->mexp > r2_ptr->mexp) return FALSE; + + /* Compare indexes */ + return w1 <= w2; +} + +/*! +* @brief nestのモンスターリストをスワップするための関数 / +* Swap function for sorting nest monster information +* @param u スワップ処理対象配列ポインタ +* @param v 未使用 +* @param a スワップ対象参照ID1 +* @param b スワップ対象参照ID2 +*/ +static void ang_sort_swap_nest_mon_info(vptr u, vptr v, int a, int b) +{ + nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; + nest_mon_info_type holder; + + /* Unused */ + (void)v; + + /* Swap */ + holder = nest_mon_info[a]; + nest_mon_info[a] = nest_mon_info[b]; + nest_mon_info[b] = holder; +} + + + +/*!nest情報テーブル*/ +static vault_aux_type nest_types[] = +{ + { _("クローン", "clone"), vault_aux_clone, vault_prep_clone, 5, 3 }, + { _("ゼリー", "jelly"), vault_aux_jelly, NULL, 5, 6 }, + { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 }, + { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 }, + { _("ミミック", "mimic"), vault_aux_mimic, NULL, 30, 4 }, + { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 70, 2 }, + { _("犬小屋", "kennel"), vault_aux_kennel, NULL, 45, 4 }, + { _("動物園", "animal"), vault_aux_animal, NULL, 35, 5 }, + { _("教会", "chapel"), vault_aux_chapel_g, NULL, 75, 4 }, + { _("アンデッド", "undead"), vault_aux_undead, NULL, 75, 5 }, + { NULL, NULL, NULL, 0, 0 }, +}; + +/*!pit情報テーブル*/ +static vault_aux_type pit_types[] = +{ + { _("オーク", "orc"), vault_aux_orc, NULL, 5, 6 }, + { _("トロル", "troll"), vault_aux_troll, NULL, 20, 6 }, + { _("ジャイアント", "giant"), vault_aux_giant, NULL, 50, 6 }, + { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 80, 2 }, + { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 }, + { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 }, + { _("教会", "chapel"), vault_aux_chapel_g, NULL, 65, 2 }, + { _("ドラゴン", "dragon"), vault_aux_dragon, vault_prep_dragon, 70, 6 }, + { _("デーモン", "demon"), vault_aux_demon, NULL, 80, 6 }, + { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL, 45, 4 }, + { NULL, NULL, NULL, 0, 0 }, +}; + + + + +/*! +* @brief タイプ5の部屋…nestを生成する / Type 5 -- Monster nests +* @return なし +* @details +* A monster nest is a "big" room, with an "inner" room, containing\n +* a "collection" of monsters of a given type strewn about the room.\n +*\n +* The monsters are chosen from a set of 64 randomly selected monster\n +* races, to allow the nest creation to fail instead of having "holes".\n +*\n +* Note the use of the "get_mon_num_prep()" function, and the special\n +* "get_mon_num_hook()" restriction function, to prepare the "monster\n +* allocation table" in such a way as to optimize the selection of\n +* "appropriate" non-unique monsters for the nest.\n +*\n +* Note that the "get_mon_num()" function may (rarely) fail, in which\n +* case the nest will be empty.\n +*\n +* Note that "monster nests" will never contain "unique" monsters.\n +*/ +bool build_type5(void) +{ + POSITION y, x, y1, x1, y2, x2, xval, yval; + int i; + nest_mon_info_type nest_mon_info[NUM_NEST_MON_TYPE]; + + monster_type align; + + cave_type *c_ptr; + + int cur_nest_type = pick_vault_type(nest_types, d_info[p_ptr->dungeon_idx].nest); + vault_aux_type *n_ptr; + + /* No type available */ + if (cur_nest_type < 0) return FALSE; + + n_ptr = &nest_types[cur_nest_type]; + + /* Process a preparation function if necessary */ + if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + get_mon_num_prep(n_ptr->hook_func, NULL); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < NUM_NEST_MON_TYPE; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 11); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + nest_mon_info[i].r_idx = (s16b)r_idx; + nest_mon_info[i].used = FALSE; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + /* Large room */ + y1 = yval - 4; + y2 = yval + 4; + x1 = xval - 11; + x2 = xval + 11; + + /* Place the floor area */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + } + } + + /* Place the outer walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + + /* Advance to the center room */ + y1 = y1 + 2; + y2 = y2 - 2; + x1 = x1 + 2; + x2 = x2 - 2; + + /* The inner walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_inner_grid(c_ptr); + } + + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_inner_grid(c_ptr); + } + for (y = y1; y <= y2; y++) + { + for (x = x1; x <= x2; x++) + { + add_cave_info(y, x, CAVE_ICKY); + } + } + + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, TRUE)); + + /* Place some monsters */ + for (y = yval - 2; y <= yval + 2; y++) + { + for (x = xval - 9; x <= xval + 9; x++) + { + MONRACE_IDX r_idx; + + i = randint0(NUM_NEST_MON_TYPE); + r_idx = nest_mon_info[i].r_idx; + + /* Place that "random" monster (no groups) */ + (void)place_monster_aux(0, y, x, r_idx, 0L); + + nest_mon_info[i].used = TRUE; + } + } + + if (cheat_room) + { + ang_sort_comp = ang_sort_comp_nest_mon_info; + ang_sort_swap = ang_sort_swap_nest_mon_info; + ang_sort(nest_mon_info, NULL, NUM_NEST_MON_TYPE); + + /* Dump the entries (prevent multi-printing) */ + for (i = 0; i < NUM_NEST_MON_TYPE; i++) + { + if (!nest_mon_info[i].used) break; + for (; i < NUM_NEST_MON_TYPE - 1; i++) + { + if (nest_mon_info[i].r_idx != nest_mon_info[i + 1].r_idx) break; + if (!nest_mon_info[i + 1].used) break; + } + msg_format_wizard(CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, r_name + r_info[nest_mon_info[i].r_idx].name); + } + } + + return TRUE; +} + + +/*! +* @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits +* @return なし +* @details +* A monster pit is a "big" room, with an "inner" room, containing\n +* a "collection" of monsters of a given type organized in the room.\n +*\n +* The inside room in a monster pit appears as shown below, where the\n +* actual monsters in each location depend on the type of the pit\n +*\n +* XXXXXXXXXXXXXXXXXXXXX\n +* X0000000000000000000X\n +* X0112233455543322110X\n +* X0112233467643322110X\n +* X0112233455543322110X\n +* X0000000000000000000X\n +* XXXXXXXXXXXXXXXXXXXXX\n +*\n +* Note that the monsters in the pit are now chosen by using "get_mon_num()"\n +* to request 16 "appropriate" monsters, sorting them by level, and using\n +* the "even" entries in this sorted list for the contents of the pit.\n +*\n +* Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n +* which is handled by requiring a specific "breath" attack for all of the\n +* dragons. This may include "multi-hued" breath. Note that "wyrms" may\n +* be present in many of the dragon pits, if they have the proper breath.\n +*\n +* Note the use of the "get_mon_num_prep()" function, and the special\n +* "get_mon_num_hook()" restriction function, to prepare the "monster\n +* allocation table" in such a way as to optimize the selection of\n +* "appropriate" non-unique monsters for the pit.\n +*\n +* Note that the "get_mon_num()" function may (rarely) fail, in which case\n +* the pit will be empty.\n +*\n +* Note that "monster pits" will never contain "unique" monsters.\n +*/ +bool build_type6(void) +{ + POSITION y, x, y1, x1, y2, x2, xval, yval; + int i, j; + + MONRACE_IDX what[16]; + + monster_type align; + + cave_type *c_ptr; + + int cur_pit_type = pick_vault_type(pit_types, d_info[p_ptr->dungeon_idx].pit); + vault_aux_type *n_ptr; + + /* No type available */ + if (cur_pit_type < 0) return FALSE; + + n_ptr = &pit_types[cur_pit_type]; + + /* Process a preparation function if necessary */ + if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + get_mon_num_prep(n_ptr->hook_func, NULL); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < 16; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 11); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + what[i] = r_idx; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + /* Large room */ + y1 = yval - 4; + y2 = yval + 4; + x1 = xval - 11; + x2 = xval + 11; + + /* Place the floor area */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + } + } + + /* Place the outer walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + /* Advance to the center room */ + y1 = y1 + 2; + y2 = y2 - 2; + x1 = x1 + 2; + x2 = x2 - 2; + + /* The inner walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_inner_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_inner_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_inner_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_inner_grid(c_ptr); + } + for (y = y1; y <= y2; y++) + { + for (x = x1; x <= x2; x++) + { + add_cave_info(y, x, CAVE_ICKY); + } + } + + /* Place a secret door */ + switch (randint1(4)) + { + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; + } + + /* Sort the entries */ + for (i = 0; i < 16 - 1; i++) + { + /* Sort the entries */ + for (j = 0; j < 16 - 1; j++) + { + int i1 = j; + int i2 = j + 1; + + int p1 = r_info[what[i1]].level; + int p2 = r_info[what[i2]].level; + + /* Bubble */ + if (p1 > p2) + { + MONRACE_IDX tmp = what[i1]; + what[i1] = what[i2]; + what[i2] = tmp; + } + } + } + + msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); + + /* Select the entries */ + for (i = 0; i < 8; i++) + { + /* Every other entry */ + what[i] = what[i * 2]; + msg_format_wizard(CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_name + r_info[what[i]].name); + } + + /* Top and bottom rows */ + for (x = xval - 9; x <= xval + 9; x++) + { + place_monster_aux(0, yval - 2, x, what[0], PM_NO_KAGE); + place_monster_aux(0, yval + 2, x, what[0], PM_NO_KAGE); + } + + /* Middle columns */ + for (y = yval - 1; y <= yval + 1; y++) + { + place_monster_aux(0, y, xval - 9, what[0], PM_NO_KAGE); + place_monster_aux(0, y, xval + 9, what[0], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 8, what[1], PM_NO_KAGE); + place_monster_aux(0, y, xval + 8, what[1], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 7, what[1], PM_NO_KAGE); + place_monster_aux(0, y, xval + 7, what[1], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 6, what[2], PM_NO_KAGE); + place_monster_aux(0, y, xval + 6, what[2], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 5, what[2], PM_NO_KAGE); + place_monster_aux(0, y, xval + 5, what[2], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 4, what[3], PM_NO_KAGE); + place_monster_aux(0, y, xval + 4, what[3], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 3, what[3], PM_NO_KAGE); + place_monster_aux(0, y, xval + 3, what[3], PM_NO_KAGE); + + place_monster_aux(0, y, xval - 2, what[4], PM_NO_KAGE); + place_monster_aux(0, y, xval + 2, what[4], PM_NO_KAGE); + } + + /* Above/Below the center monster */ + for (x = xval - 1; x <= xval + 1; x++) + { + place_monster_aux(0, yval + 1, x, what[5], PM_NO_KAGE); + place_monster_aux(0, yval - 1, x, what[5], PM_NO_KAGE); + } + + /* Next to the center monster */ + place_monster_aux(0, yval, xval + 1, what[6], PM_NO_KAGE); + place_monster_aux(0, yval, xval - 1, what[6], PM_NO_KAGE); + + /* Center monster */ + place_monster_aux(0, yval, xval, what[7], PM_NO_KAGE); + + return TRUE; +} + + + +/* +* Helper function for "trapped monster pit" +*/ +static bool vault_aux_trapped_pit(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; + + if (!vault_monster_okay(r_idx)) return (FALSE); + + /* No wall passing monster */ + if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE); + + return (TRUE); +} + + +/*! +* @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits +* @return なし +* @details +* A trapped monster pit is a "big" room with a straight corridor in\n +* which wall opening traps are placed, and with two "inner" rooms\n +* containing a "collection" of monsters of a given type organized in\n +* the room.\n +*\n +* The trapped monster pit appears as shown below, where the actual\n +* monsters in each location depend on the type of the pit\n +*\n +* XXXXXXXXXXXXXXXXXXXXXXXXX\n +* X X\n +* XXXXXXXXXXXXXXXXXXXXXXX X\n +* XXXXX001123454321100XXX X\n +* XXX0012234567654322100X X\n +* XXXXXXXXXXXXXXXXXXXXXXX X\n +* X ^ X\n +* X XXXXXXXXXXXXXXXXXXXXXXX\n +* X X0012234567654322100XXX\n +* X XXX001123454321100XXXXX\n +* X XXXXXXXXXXXXXXXXXXXXXXX\n +* X X\n +* XXXXXXXXXXXXXXXXXXXXXXXXX\n +*\n +* Note that the monsters in the pit are now chosen by using "get_mon_num()"\n +* to request 16 "appropriate" monsters, sorting them by level, and using\n +* the "even" entries in this sorted list for the contents of the pit.\n +*\n +* Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n +* which is handled by requiring a specific "breath" attack for all of the\n +* dragons. This may include "multi-hued" breath. Note that "wyrms" may\n +* be present in many of the dragon pits, if they have the proper breath.\n +*\n +* Note the use of the "get_mon_num_prep()" function, and the special\n +* "get_mon_num_hook()" restriction function, to prepare the "monster\n +* allocation table" in such a way as to optimize the selection of\n +* "appropriate" non-unique monsters for the pit.\n +*\n +* Note that the "get_mon_num()" function may (rarely) fail, in which case\n +* the pit will be empty.\n +*\n +* Note that "monster pits" will never contain "unique" monsters.\n +*/ +bool build_type13(void) +{ + static int placing[][3] = { + { -2, -9, 0 },{ -2, -8, 0 },{ -3, -7, 0 },{ -3, -6, 0 }, + { +2, -9, 0 },{ +2, -8, 0 },{ +3, -7, 0 },{ +3, -6, 0 }, + { -2, +9, 0 },{ -2, +8, 0 },{ -3, +7, 0 },{ -3, +6, 0 }, + { +2, +9, 0 },{ +2, +8, 0 },{ +3, +7, 0 },{ +3, +6, 0 }, + { -2, -7, 1 },{ -3, -5, 1 },{ -3, -4, 1 }, + { +2, -7, 1 },{ +3, -5, 1 },{ +3, -4, 1 }, + { -2, +7, 1 },{ -3, +5, 1 },{ -3, +4, 1 }, + { +2, +7, 1 },{ +3, +5, 1 },{ +3, +4, 1 }, + { -2, -6, 2 },{ -2, -5, 2 },{ -3, -3, 2 }, + { +2, -6, 2 },{ +2, -5, 2 },{ +3, -3, 2 }, + { -2, +6, 2 },{ -2, +5, 2 },{ -3, +3, 2 }, + { +2, +6, 2 },{ +2, +5, 2 },{ +3, +3, 2 }, + { -2, -4, 3 },{ -3, -2, 3 }, + { +2, -4, 3 },{ +3, -2, 3 }, + { -2, +4, 3 },{ -3, +2, 3 }, + { +2, +4, 3 },{ +3, +2, 3 }, + { -2, -3, 4 },{ -3, -1, 4 }, + { +2, -3, 4 },{ +3, -1, 4 }, + { -2, +3, 4 },{ -3, +1, 4 }, + { +2, +3, 4 },{ +3, +1, 4 }, + { -2, -2, 5 },{ -3, 0, 5 },{ -2, +2, 5 }, + { +2, -2, 5 },{ +3, 0, 5 },{ +2, +2, 5 }, + { -2, -1, 6 },{ -2, +1, 6 }, + { +2, -1, 6 },{ +2, +1, 6 }, + { -2, 0, 7 },{ +2, 0, 7 }, + { 0, 0, -1 } + }; + + POSITION y, x, y1, x1, y2, x2, xval, yval; + int i, j; + + MONRACE_IDX what[16]; + + monster_type align; + + cave_type *c_ptr; + + int cur_pit_type = pick_vault_type(pit_types, d_info[p_ptr->dungeon_idx].pit); + vault_aux_type *n_ptr; + + /* Only in Angband */ + if (p_ptr->dungeon_idx != DUNGEON_ANGBAND) return FALSE; + + /* No type available */ + if (cur_pit_type < 0) return FALSE; + + n_ptr = &pit_types[cur_pit_type]; + + /* Process a preparation function if necessary */ + if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < 16; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 0); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + what[i] = r_idx; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 13, 25)) return FALSE; + + /* Large room */ + y1 = yval - 5; + y2 = yval + 5; + x1 = xval - 11; + x2 = xval + 11; + + /* Fill with inner walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + } + } + + /* Place the floor area 1 */ + for (x = x1 + 3; x <= x2 - 3; x++) + { + c_ptr = &cave[yval - 2][x]; + place_floor_grid(c_ptr); + add_cave_info(yval - 2, x, CAVE_ICKY); + + c_ptr = &cave[yval + 2][x]; + place_floor_grid(c_ptr); + add_cave_info(yval + 2, x, CAVE_ICKY); + } + + /* Place the floor area 2 */ + for (x = x1 + 5; x <= x2 - 5; x++) + { + c_ptr = &cave[yval - 3][x]; + place_floor_grid(c_ptr); + add_cave_info(yval - 3, x, CAVE_ICKY); + + c_ptr = &cave[yval + 3][x]; + place_floor_grid(c_ptr); + add_cave_info(yval + 3, x, CAVE_ICKY); + } + + /* Corridor */ + for (x = x1; x <= x2; x++) + { + c_ptr = &cave[yval][x]; + place_floor_grid(c_ptr); + c_ptr = &cave[y1][x]; + place_floor_grid(c_ptr); + c_ptr = &cave[y2][x]; + place_floor_grid(c_ptr); + } + + /* Place the outer walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + /* Random corridor */ + if (one_in_(2)) + { + for (y = y1; y <= yval; y++) + { + place_floor_bold(y, x2); + place_solid_bold(y, x1 - 1); + } + for (y = yval; y <= y2 + 1; y++) + { + place_floor_bold(y, x1); + place_solid_bold(y, x2 + 1); + } + } + else + { + for (y = yval; y <= y2 + 1; y++) + { + place_floor_bold(y, x1); + place_solid_bold(y, x2 + 1); + } + for (y = y1; y <= yval; y++) + { + place_floor_bold(y, x2); + place_solid_bold(y, x1 - 1); + } + } + + /* Place the wall open trap */ + cave[yval][xval].mimic = cave[yval][xval].feat; + cave[yval][xval].feat = feat_trap_open; + + /* Sort the entries */ + for (i = 0; i < 16 - 1; i++) + { + /* Sort the entries */ + for (j = 0; j < 16 - 1; j++) + { + int i1 = j; + int i2 = j + 1; + + int p1 = r_info[what[i1]].level; + int p2 = r_info[what[i2]].level; + + /* Bubble */ + if (p1 > p2) + { + MONRACE_IDX tmp = what[i1]; + what[i1] = what[i2]; + what[i2] = tmp; + } + } + } + + msg_format_wizard(CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), + n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); + + /* Select the entries */ + for (i = 0; i < 8; i++) + { + /* Every other entry */ + what[i] = what[i * 2]; + + if (cheat_hear) + { + msg_print(r_name + r_info[what[i]].name); + } + } + + for (i = 0; placing[i][2] >= 0; i++) + { + y = yval + placing[i][0]; + x = xval + placing[i][1]; + place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE); + } + + return TRUE; +} + diff --git a/src/rooms-pitnest.h b/src/rooms-pitnest.h index 9e0fe24a2..21b6640ce 100644 --- a/src/rooms-pitnest.h +++ b/src/rooms-pitnest.h @@ -1,12 +1,12 @@ - -/*! デバッグ時にnestのモンスター情報を確認するための構造体 / A struct for nest monster information with cheat_hear */ -typedef struct -{ - MONRACE_IDX r_idx; - bool used; -} -nest_mon_info_type; - -extern bool build_type5(void); -extern bool build_type6(void); -extern bool build_type13(void); + +/*! デバッグ時にnestのモンスター情報を確認するための構造体 / A struct for nest monster information with cheat_hear */ +typedef struct +{ + MONRACE_IDX r_idx; + bool used; +} +nest_mon_info_type; + +extern bool build_type5(void); +extern bool build_type6(void); +extern bool build_type13(void); diff --git a/src/rooms-special.c b/src/rooms-special.c index 915e99e88..e2a239a04 100644 --- a/src/rooms-special.c +++ b/src/rooms-special.c @@ -1,242 +1,242 @@ -#include "angband.h" -#include "grid.h" -#include "generate.h" -#include "rooms.h" -#include "monster.h" -#include "monsterrace-hook.h" -#include "objectkind-hook.h" - - -/*! -* @brief タイプ15の部屋…ガラス部屋の生成 / Type 15 -- glass rooms -* @return なし -*/ -bool build_type15(void) -{ - POSITION y, x, y2, x2, yval, xval; - POSITION y1, x1, xsize, ysize; - bool light; - - cave_type *c_ptr; - - /* Pick a room size */ - xsize = rand_range(9, 13); - ysize = rand_range(9, 13); - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - /* Get corner values */ - y1 = yval - ysize / 2; - x1 = xval - xsize / 2; - y2 = yval + (ysize - 1) / 2; - x2 = xval + (xsize - 1) / 2; - - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->feat = feat_glass_floor; - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Walls around the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - - switch (randint1(3)) - { - case 1: /* 4 lite breathers + potion */ - { - int dir1, dir2; - get_mon_num_prep(vault_aux_lite, NULL); - - /* Place fixed lite berathers */ - for (dir1 = 4; dir1 < 8; dir1++) - { - MONRACE_IDX r_idx = get_mon_num(dun_level); - - y = yval + 2 * ddy_ddd[dir1]; - x = xval + 2 * ddx_ddd[dir1]; - if (r_idx) place_monster_aux(0, y, x, r_idx, PM_ALLOW_SLEEP); - - /* Walls around the breather */ - for (dir2 = 0; dir2 < 8; dir2++) - { - c_ptr = &cave[y + ddy_ddd[dir2]][x + ddx_ddd[dir2]]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - } - - /* Walls around the potion */ - for (dir1 = 0; dir1 < 4; dir1++) - { - y = yval + 2 * ddy_ddd[dir1]; - x = xval + 2 * ddx_ddd[dir1]; - c_ptr = &cave[y][x]; - place_inner_perm_grid(c_ptr); - c_ptr->feat = feat_permanent_glass_wall; - cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]].info |= (CAVE_ICKY); - } - - /* Glass door */ - dir1 = randint0(4); - y = yval + 2 * ddy_ddd[dir1]; - x = xval + 2 * ddx_ddd[dir1]; - place_secret_door(y, x, DOOR_GLASS_DOOR); - c_ptr = &cave[y][x]; - if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; - - /* Place a potion */ - get_obj_num_hook = kind_is_potion; - place_object(yval, xval, AM_NO_FIXED_ART); - cave[yval][xval].info |= (CAVE_ICKY); - } - break; - - case 2: /* 1 lite breather + random object */ - { - MONRACE_IDX r_idx; - DIRECTION dir1; - - /* Pillars */ - c_ptr = &cave[y1 + 1][x1 + 1]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - - c_ptr = &cave[y1 + 1][x2 - 1]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - - c_ptr = &cave[y2 - 1][x1 + 1]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - - c_ptr = &cave[y2 - 1][x2 - 1]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - get_mon_num_prep(vault_aux_lite, NULL); - - r_idx = get_mon_num(dun_level); - if (r_idx) place_monster_aux(0, yval, xval, r_idx, 0L); - - /* Walls around the breather */ - for (dir1 = 0; dir1 < 8; dir1++) - { - c_ptr = &cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - - /* Curtains around the breather */ - for (y = yval - 1; y <= yval + 1; y++) - { - place_closed_door(y, xval - 2, DOOR_CURTAIN); - place_closed_door(y, xval + 2, DOOR_CURTAIN); - } - for (x = xval - 1; x <= xval + 1; x++) - { - place_closed_door(yval - 2, x, DOOR_CURTAIN); - place_closed_door(yval + 2, x, DOOR_CURTAIN); - } - - /* Place an object */ - place_object(yval, xval, AM_NO_FIXED_ART); - cave[yval][xval].info |= (CAVE_ICKY); - } - break; - - case 3: /* 4 shards breathers + 2 potions */ - { - DIRECTION dir1; - - /* Walls around the potion */ - for (y = yval - 2; y <= yval + 2; y++) - { - c_ptr = &cave[y][xval - 3]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - c_ptr = &cave[y][xval + 3]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - for (x = xval - 2; x <= xval + 2; x++) - { - c_ptr = &cave[yval - 3][x]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - c_ptr = &cave[yval + 3][x]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - for (dir1 = 4; dir1 < 8; dir1++) - { - c_ptr = &cave[yval + 2 * ddy_ddd[dir1]][xval + 2 * ddx_ddd[dir1]]; - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - } - get_mon_num_prep(vault_aux_shards, NULL); - - /* Place shard berathers */ - for (dir1 = 4; dir1 < 8; dir1++) - { - MONRACE_IDX r_idx = get_mon_num(dun_level); - - y = yval + ddy_ddd[dir1]; - x = xval + ddx_ddd[dir1]; - if (r_idx) place_monster_aux(0, y, x, r_idx, 0L); - } - - /* Place two potions */ - if (one_in_(2)) - { - get_obj_num_hook = kind_is_potion; - place_object(yval, xval - 1, AM_NO_FIXED_ART); - get_obj_num_hook = kind_is_potion; - place_object(yval, xval + 1, AM_NO_FIXED_ART); - } - else - { - get_obj_num_hook = kind_is_potion; - place_object(yval - 1, xval, AM_NO_FIXED_ART); - get_obj_num_hook = kind_is_potion; - place_object(yval + 1, xval, AM_NO_FIXED_ART); - } - - for (y = yval - 2; y <= yval + 2; y++) - for (x = xval - 2; x <= xval + 2; x++) - cave[y][x].info |= (CAVE_ICKY); - - } - break; - } - - msg_print_wizard(CHEAT_DUNGEON, _("ガラスの部屋が生成されました。", "Glass room was generated.")); - - return TRUE; -} +#include "angband.h" +#include "grid.h" +#include "generate.h" +#include "rooms.h" +#include "monster.h" +#include "monsterrace-hook.h" +#include "objectkind-hook.h" + + +/*! +* @brief タイプ15の部屋…ガラス部屋の生成 / Type 15 -- glass rooms +* @return なし +*/ +bool build_type15(void) +{ + POSITION y, x, y2, x2, yval, xval; + POSITION y1, x1, xsize, ysize; + bool light; + + cave_type *c_ptr; + + /* Pick a room size */ + xsize = rand_range(9, 13); + ysize = rand_range(9, 13); + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + /* Get corner values */ + y1 = yval - ysize / 2; + x1 = xval - xsize / 2; + y2 = yval + (ysize - 1) / 2; + x2 = xval + (xsize - 1) / 2; + + /* Place a full floor under the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->feat = feat_glass_floor; + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Walls around the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + + switch (randint1(3)) + { + case 1: /* 4 lite breathers + potion */ + { + int dir1, dir2; + get_mon_num_prep(vault_aux_lite, NULL); + + /* Place fixed lite berathers */ + for (dir1 = 4; dir1 < 8; dir1++) + { + MONRACE_IDX r_idx = get_mon_num(dun_level); + + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + if (r_idx) place_monster_aux(0, y, x, r_idx, PM_ALLOW_SLEEP); + + /* Walls around the breather */ + for (dir2 = 0; dir2 < 8; dir2++) + { + c_ptr = &cave[y + ddy_ddd[dir2]][x + ddx_ddd[dir2]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + } + + /* Walls around the potion */ + for (dir1 = 0; dir1 < 4; dir1++) + { + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + c_ptr = &cave[y][x]; + place_inner_perm_grid(c_ptr); + c_ptr->feat = feat_permanent_glass_wall; + cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]].info |= (CAVE_ICKY); + } + + /* Glass door */ + dir1 = randint0(4); + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + place_secret_door(y, x, DOOR_GLASS_DOOR); + c_ptr = &cave[y][x]; + if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; + + /* Place a potion */ + get_obj_num_hook = kind_is_potion; + place_object(yval, xval, AM_NO_FIXED_ART); + cave[yval][xval].info |= (CAVE_ICKY); + } + break; + + case 2: /* 1 lite breather + random object */ + { + MONRACE_IDX r_idx; + DIRECTION dir1; + + /* Pillars */ + c_ptr = &cave[y1 + 1][x1 + 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y1 + 1][x2 - 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y2 - 1][x1 + 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y2 - 1][x2 - 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + get_mon_num_prep(vault_aux_lite, NULL); + + r_idx = get_mon_num(dun_level); + if (r_idx) place_monster_aux(0, yval, xval, r_idx, 0L); + + /* Walls around the breather */ + for (dir1 = 0; dir1 < 8; dir1++) + { + c_ptr = &cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + + /* Curtains around the breather */ + for (y = yval - 1; y <= yval + 1; y++) + { + place_closed_door(y, xval - 2, DOOR_CURTAIN); + place_closed_door(y, xval + 2, DOOR_CURTAIN); + } + for (x = xval - 1; x <= xval + 1; x++) + { + place_closed_door(yval - 2, x, DOOR_CURTAIN); + place_closed_door(yval + 2, x, DOOR_CURTAIN); + } + + /* Place an object */ + place_object(yval, xval, AM_NO_FIXED_ART); + cave[yval][xval].info |= (CAVE_ICKY); + } + break; + + case 3: /* 4 shards breathers + 2 potions */ + { + DIRECTION dir1; + + /* Walls around the potion */ + for (y = yval - 2; y <= yval + 2; y++) + { + c_ptr = &cave[y][xval - 3]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[y][xval + 3]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + for (x = xval - 2; x <= xval + 2; x++) + { + c_ptr = &cave[yval - 3][x]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[yval + 3][x]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + for (dir1 = 4; dir1 < 8; dir1++) + { + c_ptr = &cave[yval + 2 * ddy_ddd[dir1]][xval + 2 * ddx_ddd[dir1]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + get_mon_num_prep(vault_aux_shards, NULL); + + /* Place shard berathers */ + for (dir1 = 4; dir1 < 8; dir1++) + { + MONRACE_IDX r_idx = get_mon_num(dun_level); + + y = yval + ddy_ddd[dir1]; + x = xval + ddx_ddd[dir1]; + if (r_idx) place_monster_aux(0, y, x, r_idx, 0L); + } + + /* Place two potions */ + if (one_in_(2)) + { + get_obj_num_hook = kind_is_potion; + place_object(yval, xval - 1, AM_NO_FIXED_ART); + get_obj_num_hook = kind_is_potion; + place_object(yval, xval + 1, AM_NO_FIXED_ART); + } + else + { + get_obj_num_hook = kind_is_potion; + place_object(yval - 1, xval, AM_NO_FIXED_ART); + get_obj_num_hook = kind_is_potion; + place_object(yval + 1, xval, AM_NO_FIXED_ART); + } + + for (y = yval - 2; y <= yval + 2; y++) + for (x = xval - 2; x <= xval + 2; x++) + cave[y][x].info |= (CAVE_ICKY); + + } + break; + } + + msg_print_wizard(CHEAT_DUNGEON, _("ガラスの部屋が生成されました。", "Glass room was generated.")); + + return TRUE; +} diff --git a/src/rooms-special.h b/src/rooms-special.h index 8561f2efb..179e0d8b1 100644 --- a/src/rooms-special.h +++ b/src/rooms-special.h @@ -1,2 +1,2 @@ -extern bool build_type15(void); - +extern bool build_type15(void); + diff --git a/src/rooms-trap.c b/src/rooms-trap.c index 39dd33ed2..c3a9597b6 100644 --- a/src/rooms-trap.c +++ b/src/rooms-trap.c @@ -1,88 +1,88 @@ -#include "angband.h" -#include "grid.h" -#include "generate.h" -#include "rooms.h" - - -/*! -* @brief タイプ14の部屋…特殊トラップ部屋の生成 / Type 14 -- trapped rooms -* @return なし -* @details -* A special trap is placed at center of the room -*/ -bool build_type14(void) -{ - POSITION y, x, y2, x2, yval, xval; - POSITION y1, x1, xsize, ysize; - - bool light; - - cave_type *c_ptr; - s16b trap; - - /* Pick a room size */ - y1 = randint1(4); - x1 = randint1(11); - y2 = randint1(3); - x2 = randint1(11); - - xsize = x1 + x2 + 1; - ysize = y1 + y2 + 1; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); - - - /* Get corner values */ - y1 = yval - ysize / 2; - x1 = xval - xsize / 2; - y2 = yval + (ysize - 1) / 2; - x2 = xval + (xsize - 1) / 2; - - - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } - - /* Walls around the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } - - if (dun_level < 30 + randint1(30)) - trap = feat_trap_piranha; - else - trap = feat_trap_armageddon; - - /* Place a special trap */ - c_ptr = &cave[rand_spread(yval, ysize / 4)][rand_spread(xval, xsize / 4)]; - c_ptr->mimic = c_ptr->feat; - c_ptr->feat = trap; - - msg_format_wizard(CHEAT_DUNGEON, _("%sの部屋が生成されました。", "Room of %s was generated."), f_name + f_info[trap].name); - - return TRUE; -} - +#include "angband.h" +#include "grid.h" +#include "generate.h" +#include "rooms.h" + + +/*! +* @brief タイプ14の部屋…特殊トラップ部屋の生成 / Type 14 -- trapped rooms +* @return なし +* @details +* A special trap is placed at center of the room +*/ +bool build_type14(void) +{ + POSITION y, x, y2, x2, yval, xval; + POSITION y1, x1, xsize, ysize; + + bool light; + + cave_type *c_ptr; + s16b trap; + + /* Pick a room size */ + y1 = randint1(4); + x1 = randint1(11); + y2 = randint1(3); + x2 = randint1(11); + + xsize = x1 + x2 + 1; + ysize = y1 + y2 + 1; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS)); + + + /* Get corner values */ + y1 = yval - ysize / 2; + x1 = xval - xsize / 2; + y2 = yval + (ysize - 1) / 2; + x2 = xval + (xsize - 1) / 2; + + + /* Place a full floor under the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Walls around the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + if (dun_level < 30 + randint1(30)) + trap = feat_trap_piranha; + else + trap = feat_trap_armageddon; + + /* Place a special trap */ + c_ptr = &cave[rand_spread(yval, ysize / 4)][rand_spread(xval, xsize / 4)]; + c_ptr->mimic = c_ptr->feat; + c_ptr->feat = trap; + + msg_format_wizard(CHEAT_DUNGEON, _("%sの部屋が生成されました。", "Room of %s was generated."), f_name + f_info[trap].name); + + return TRUE; +} + diff --git a/src/rooms-trap.h b/src/rooms-trap.h index d3063c648..abcc60965 100644 --- a/src/rooms-trap.h +++ b/src/rooms-trap.h @@ -1 +1 @@ -extern bool build_type14(void); +extern bool build_type14(void); diff --git a/src/rooms-vault.c b/src/rooms-vault.c index f21ec719c..8c2f98895 100644 --- a/src/rooms-vault.c +++ b/src/rooms-vault.c @@ -1,1301 +1,1301 @@ -#include "angband.h" -#include "generate.h" -#include "grid.h" -#include "rooms.h" -#include "store.h" -#include "trap.h" -#include "monster.h" - -/* -* This function creates a random vault that looks like a collection of bubbles. -* It works by getting a set of coordinates that represent the center of each -* bubble. The entire room is made by seeing which bubble center is closest. If -* two centers are equidistant then the square is a wall, otherwise it is a floor. -* The only exception is for squares really near a center, these are always floor. -* (It looks better than without this check.) -* -* Note: If two centers are on the same point then this algorithm will create a -* blank bubble filled with walls. - This is prevented from happening. -*/ -static void build_bubble_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) -{ -#define BUBBLENUM 10 /* number of bubbles */ - - /* array of center points of bubbles */ - coord center[BUBBLENUM]; - - int i, j; - POSITION x = 0, y = 0; - u16b min1, min2, temp; - bool done; - - /* Offset from center to top left hand corner */ - POSITION xhsize = xsize / 2; - POSITION yhsize = ysize / 2; - - msg_print_wizard(CHEAT_DUNGEON, _("泡型ランダムVaultを生成しました。", "Room Vault.")); - - /* Allocate center of bubbles */ - center[0].x = (byte)randint1(xsize - 3) + 1; - center[0].y = (byte)randint1(ysize - 3) + 1; - - for (i = 1; i < BUBBLENUM; i++) - { - done = FALSE; - - /* get center and check to see if it is unique */ - while (!done) - { - done = TRUE; - - x = randint1(xsize - 3) + 1; - y = randint1(ysize - 3) + 1; - - for (j = 0; j < i; j++) - { - /* rough test to see if there is an overlap */ - if ((x == center[j].x) && (y == center[j].y)) done = FALSE; - } - } - - center[i].x = x; - center[i].y = y; - } - - - /* Top and bottom boundaries */ - for (i = 0; i < xsize; i++) - { - int side_x = x0 - xhsize + i; - - place_outer_noperm_bold(y0 - yhsize + 0, side_x); - cave[y0 - yhsize + 0][side_x].info |= (CAVE_ROOM | CAVE_ICKY); - place_outer_noperm_bold(y0 - yhsize + ysize - 1, side_x); - cave[y0 - yhsize + ysize - 1][side_x].info |= (CAVE_ROOM | CAVE_ICKY); - } - - /* Left and right boundaries */ - for (i = 1; i < ysize - 1; i++) - { - int side_y = y0 - yhsize + i; - - place_outer_noperm_bold(side_y, x0 - xhsize + 0); - cave[side_y][x0 - xhsize + 0].info |= (CAVE_ROOM | CAVE_ICKY); - place_outer_noperm_bold(side_y, x0 - xhsize + xsize - 1); - cave[side_y][x0 - xhsize + xsize - 1].info |= (CAVE_ROOM | CAVE_ICKY); - } - - /* Fill in middle with bubbles */ - for (x = 1; x < xsize - 1; x++) - { - for (y = 1; y < ysize - 1; y++) - { - /* Get distances to two closest centers */ - - min1 = (u16b)distance(x, y, center[0].x, center[0].y); - min2 = (u16b)distance(x, y, center[1].x, center[1].y); - - if (min1 > min2) - { - /* swap if in wrong order */ - temp = min1; - min1 = min2; - min2 = temp; - } - - /* Scan the rest */ - for (i = 2; i < BUBBLENUM; i++) - { - temp = (u16b)distance(x, y, center[i].x, center[i].y); - - if (temp < min1) - { - /* smallest */ - min2 = min1; - min1 = temp; - } - else if (temp < min2) - { - /* second smallest */ - min2 = temp; - } - } - if (((min2 - min1) <= 2) && (!(min1 < 3))) - { - /* Boundary at midpoint+ not at inner region of bubble */ - place_outer_noperm_bold(y0 - yhsize + y, x0 - xhsize + x); - } - else - { - /* middle of a bubble */ - place_floor_bold(y0 - yhsize + y, x0 - xhsize + x); - } - - /* clean up rest of flags */ - cave[y0 - yhsize + y][x0 - xhsize + x].info |= (CAVE_ROOM | CAVE_ICKY); - } - } - - /* Try to add some random doors */ - for (i = 0; i < 500; i++) - { - x = randint1(xsize - 3) - xhsize + x0 + 1; - y = randint1(ysize - 3) - yhsize + y0 + 1; - add_door(x, y); - } - - /* Fill with monsters and treasure, low difficulty */ - fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5)); -} - -/* Create a random vault that looks like a collection of overlapping rooms */ -static void build_room_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) -{ - POSITION x1, x2, y1, y2, xhsize, yhsize; - int i; - - /* get offset from center */ - xhsize = xsize / 2; - yhsize = ysize / 2; - - msg_print_wizard(CHEAT_DUNGEON, _("部屋型ランダムVaultを生成しました。", "Room Vault.")); - - /* fill area so don't get problems with arena levels */ - for (x1 = 0; x1 < xsize; x1++) - { - POSITION x = x0 - xhsize + x1; - - for (y1 = 0; y1 < ysize; y1++) - { - POSITION y = y0 - yhsize + y1; - - place_extra_bold(y, x); - cave[y][x].info &= (~CAVE_ICKY); - } - } - - /* add ten random rooms */ - for (i = 0; i < 10; i++) - { - x1 = randint1(xhsize) * 2 + x0 - xhsize; - x2 = randint1(xhsize) * 2 + x0 - xhsize; - y1 = randint1(yhsize) * 2 + y0 - yhsize; - y2 = randint1(yhsize) * 2 + y0 - yhsize; - build_room(x1, x2, y1, y2); - } - - /* Add some random doors */ - for (i = 0; i < 500; i++) - { - x1 = randint1(xsize - 3) - xhsize + x0 + 1; - y1 = randint1(ysize - 3) - yhsize + y0 + 1; - add_door(x1, y1); - } - - /* Fill with monsters and treasure, high difficulty */ - fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5) + 5); -} - - -/* Create a random vault out of a fractal cave */ -static void build_cave_vault(POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz) -{ - int grd, roug, cutoff; - bool done, light, room; - POSITION xhsize, yhsize, xsize, ysize, x, y; - - /* round to make sizes even */ - xhsize = xsiz / 2; - yhsize = ysiz / 2; - xsize = xhsize * 2; - ysize = yhsize * 2; - - msg_print_wizard(CHEAT_DUNGEON, _("洞穴ランダムVaultを生成しました。", "Cave Vault.")); - - light = done = FALSE; - room = TRUE; - - while (!done) - { - /* testing values for these parameters feel free to adjust */ - grd = 1 << randint0(4); - - /* want average of about 16 */ - roug = randint1(8) * randint1(4); - - /* about size/2 */ - cutoff = randint1(xsize / 4) + randint1(ysize / 4) + - randint1(xsize / 4) + randint1(ysize / 4); - - /* make it */ - generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff); - - /* Convert to normal format+ clean up */ - done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room); - } - - /* Set icky flag because is a vault */ - for (x = 0; x <= xsize; x++) - { - for (y = 0; y <= ysize; y++) - { - cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY; - } - } - - /* Fill with monsters and treasure, low difficulty */ - fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1, y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5)); -} - - - -/*! -* @brief Vault地形を回転、上下左右反転するための座標変換を返す / coordinate translation code -* @param x 変換したい点のX座標参照ポインタ -* @param y 変換したい点のY座標参照ポインタ -* @param xoffset Vault生成時の基準X座標 -* @param yoffset Vault生成時の基準Y座標 -* @param transno 処理ID -* @return なし -*/ -static void coord_trans(POSITION *x, POSITION *y, POSITION xoffset, POSITION yoffset, int transno) -{ - int i; - int temp; - - /* - * transno specifies what transformation is required. (0-7) - * The lower two bits indicate by how much the vault is rotated, - * and the upper bit indicates a reflection. - * This is done by using rotation matrices... however since - * these are mostly zeros for rotations by 90 degrees this can - * be expressed simply in terms of swapping and inverting the - * x and y coordinates. - */ - for (i = 0; i < transno % 4; i++) - { - /* rotate by 90 degrees */ - temp = *x; - *x = -(*y); - *y = temp; - } - - if (transno / 4) - { - /* Reflect depending on status of 3rd bit. */ - *x = -(*x); - } - - /* Add offsets so vault stays in the first quadrant */ - *x += xoffset; - *y += yoffset; -} - - -/*! -* @brief Vaultをフロアに配置する / Hack -- fill in "vault" rooms -* @param yval 生成基準Y座標 -* @param xval 生成基準X座標 -* @param ymax VaultのYサイズ -* @param xmax VaultのXサイズ -* @param data Vaultのデータ文字列 -* @param xoffset 変換基準X座標 -* @param yoffset 変換基準Y座標 -* @param transno 変換ID -* @return なし -*/ -static void build_vault(POSITION yval, POSITION xval, POSITION ymax, POSITION xmax, concptr data, - POSITION xoffset, POSITION yoffset, int transno) -{ - POSITION dx, dy, x, y, i, j; - concptr t; - cave_type *c_ptr; - - /* Place dungeon features and objects */ - for (t = data, dy = 0; dy < ymax; dy++) - { - for (dx = 0; dx < xmax; dx++, t++) - { - /* prevent loop counter from being overwritten */ - i = dx; - j = dy; - - /* Flip / rotate */ - coord_trans(&i, &j, xoffset, yoffset, transno); - - /* Extract the location */ - if (transno % 2 == 0) - { - /* no swap of x/y */ - x = xval - (xmax / 2) + i; - y = yval - (ymax / 2) + j; - } - else - { - /* swap of x/y */ - x = xval - (ymax / 2) + i; - y = yval - (xmax / 2) + j; - } - - /* Hack -- skip "non-grids" */ - if (*t == ' ') continue; - c_ptr = &cave[y][x]; - - /* Lay down a floor */ - place_floor_grid(c_ptr); - - /* Remove any mimic */ - c_ptr->mimic = 0; - - /* Part of a vault */ - c_ptr->info |= (CAVE_ROOM | CAVE_ICKY); - - /* Analyze the grid */ - switch (*t) - { - /* Granite wall (outer) */ - case '%': - place_outer_noperm_grid(c_ptr); - break; - - /* Granite wall (inner) */ - case '#': - place_inner_grid(c_ptr); - break; - - /* Glass wall (inner) */ - case '$': - place_inner_grid(c_ptr); - c_ptr->feat = feat_glass_wall; - break; - - /* Permanent wall (inner) */ - case 'X': - place_inner_perm_grid(c_ptr); - break; - - /* Permanent glass wall (inner) */ - case 'Y': - place_inner_perm_grid(c_ptr); - c_ptr->feat = feat_permanent_glass_wall; - break; - - /* Treasure/trap */ - case '*': - if (randint0(100) < 75) - { - place_object(y, x, 0L); - } - else - { - place_trap(y, x); - } - break; - - /* Treasure */ - case '[': - place_object(y, x, 0L); - break; - - /* Tree */ - case ':': - c_ptr->feat = feat_tree; - break; - - /* Secret doors */ - case '+': - place_secret_door(y, x, DOOR_DEFAULT); - break; - - /* Secret glass doors */ - case '-': - place_secret_door(y, x, DOOR_GLASS_DOOR); - if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; - break; - - /* Curtains */ - case '\'': - place_secret_door(y, x, DOOR_CURTAIN); - break; - - /* Trap */ - case '^': - place_trap(y, x); - break; - - /* Black market in a dungeon */ - case 'S': - set_cave_feat(y, x, feat_black_market); - store_init(NO_TOWN, STORE_BLACK); - break; - - /* The Pattern */ - case 'p': - set_cave_feat(y, x, feat_pattern_start); - break; - - case 'a': - set_cave_feat(y, x, feat_pattern_1); - break; - - case 'b': - set_cave_feat(y, x, feat_pattern_2); - break; - - case 'c': - set_cave_feat(y, x, feat_pattern_3); - break; - - case 'd': - set_cave_feat(y, x, feat_pattern_4); - break; - - case 'P': - set_cave_feat(y, x, feat_pattern_end); - break; - - case 'B': - set_cave_feat(y, x, feat_pattern_exit); - break; - - case 'A': - /* Reward for Pattern walk */ - object_level = base_level + 12; - place_object(y, x, AM_GOOD | AM_GREAT); - object_level = base_level; - break; - - case '~': - set_cave_feat(y, x, feat_shallow_water); - break; - - case '=': - set_cave_feat(y, x, feat_deep_water); - break; - - case 'v': - set_cave_feat(y, x, feat_shallow_lava); - break; - - case 'w': - set_cave_feat(y, x, feat_deep_lava); - break; - - case 'f': - set_cave_feat(y, x, feat_shallow_acid_puddle); - break; - - case 'F': - set_cave_feat(y, x, feat_deep_acid_puddle); - break; - - case 'g': - set_cave_feat(y, x, feat_shallow_poisonous_puddle); - break; - - case 'G': - set_cave_feat(y, x, feat_deep_poisonous_puddle); - break; - - case 'h': - set_cave_feat(y, x, feat_cold_zone); - break; - - case 'H': - set_cave_feat(y, x, feat_heavy_cold_zone); - break; - - case 'i': - set_cave_feat(y, x, feat_electrical_zone); - break; - - case 'I': - set_cave_feat(y, x, feat_heavy_electrical_zone); - break; - - } - } - } - - - /* Place dungeon monsters and objects */ - for (t = data, dy = 0; dy < ymax; dy++) - { - for (dx = 0; dx < xmax; dx++, t++) - { - /* prevent loop counter from being overwritten */ - i = dx; - j = dy; - - /* Flip / rotate */ - coord_trans(&i, &j, xoffset, yoffset, transno); - - /* Extract the location */ - if (transno % 2 == 0) - { - /* no swap of x/y */ - x = xval - (xmax / 2) + i; - y = yval - (ymax / 2) + j; - } - else - { - /* swap of x/y */ - x = xval - (ymax / 2) + i; - y = yval - (xmax / 2) + j; - } - - /* Hack -- skip "non-grids" */ - if (*t == ' ') continue; - - /* Analyze the symbol */ - switch (*t) - { - /* Monster */ - case '&': - { - monster_level = base_level + 5; - place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); - monster_level = base_level; - break; - } - - /* Meaner monster */ - case '@': - { - monster_level = base_level + 11; - place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); - monster_level = base_level; - break; - } - - /* Meaner monster, plus treasure */ - case '9': - { - monster_level = base_level + 9; - place_monster(y, x, PM_ALLOW_SLEEP); - monster_level = base_level; - object_level = base_level + 7; - place_object(y, x, AM_GOOD); - object_level = base_level; - break; - } - - /* Nasty monster and treasure */ - case '8': - { - monster_level = base_level + 40; - place_monster(y, x, PM_ALLOW_SLEEP); - monster_level = base_level; - object_level = base_level + 20; - place_object(y, x, AM_GOOD | AM_GREAT); - object_level = base_level; - break; - } - - /* Monster and/or object */ - case ',': - { - if (randint0(100) < 50) - { - monster_level = base_level + 3; - place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); - monster_level = base_level; - } - if (randint0(100) < 50) - { - object_level = base_level + 7; - place_object(y, x, 0L); - object_level = base_level; - } - break; - } - - } - } - } -} - - - -/*! -* @brief タイプ7の部屋…v_info.txtより小型vaultを生成する / Type 7 -- simple vaults (see "v_info.txt") -* @return なし -*/ -bool build_type7(void) -{ - vault_type *v_ptr = NULL; - int dummy; - POSITION x, y; - POSITION xval, yval; - POSITION xoffset, yoffset; - int transno; - - /* Pick a lesser vault */ - for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) - { - /* Access a random vault record */ - v_ptr = &v_info[randint0(max_v_idx)]; - - /* Accept the first lesser vault */ - if (v_ptr->typ == 7) break; - } - - /* No lesser vault found */ - if (dummy >= SAFE_MAX_ATTEMPTS) - { - msg_print_wizard(CHEAT_DUNGEON, _("小型固定Vaultを配置できませんでした。", "Could not place lesser vault.")); - return FALSE; - } - - /* pick type of transformation (0-7) */ - transno = randint0(8); - - /* calculate offsets */ - x = v_ptr->wid; - y = v_ptr->hgt; - - /* Some huge vault cannot be ratated to fit in the dungeon */ - if (x + 2 > cur_hgt - 2) - { - /* Forbid 90 or 270 degree ratation */ - transno &= ~1; - } - - coord_trans(&x, &y, 0, 0, transno); - - if (x < 0) - { - xoffset = -x - 1; - } - else - { - xoffset = 0; - } - - if (y < 0) - { - yoffset = -y - 1; - } - else - { - yoffset = 0; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, abs(y), abs(x))) return FALSE; - -#ifdef FORCE_V_IDX - v_ptr = &v_info[2]; -#endif - - msg_format_wizard(CHEAT_DUNGEON, _("小型Vault(%s)を生成しました。", "Lesser vault (%s)."), v_name + v_ptr->name); - - /* Hack -- Build the vault */ - build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, - v_text + v_ptr->text, xoffset, yoffset, transno); - - return TRUE; -} - -/*! -* @brief タイプ8の部屋…v_info.txtより大型vaultを生成する / Type 8 -- greater vaults (see "v_info.txt") -* @return なし -*/ -bool build_type8(void) -{ - vault_type *v_ptr; - int dummy; - POSITION xval, yval; - POSITION x, y; - int transno; - POSITION xoffset, yoffset; - - /* Pick a greater vault */ - for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) - { - /* Access a random vault record */ - v_ptr = &v_info[randint0(max_v_idx)]; - - /* Accept the first greater vault */ - if (v_ptr->typ == 8) break; - } - - /* No greater vault found */ - if (dummy >= SAFE_MAX_ATTEMPTS) - { - msg_print_wizard(CHEAT_DUNGEON, _("大型固定Vaultを配置できませんでした。", "Could not place greater vault.")); - return FALSE; - } - - /* pick type of transformation (0-7) */ - transno = randint0(8); - - /* calculate offsets */ - x = v_ptr->wid; - y = v_ptr->hgt; - - /* Some huge vault cannot be ratated to fit in the dungeon */ - if (x + 2 > cur_hgt - 2) - { - /* Forbid 90 or 270 degree ratation */ - transno &= ~1; - } - - coord_trans(&x, &y, 0, 0, transno); - - if (x < 0) - { - xoffset = -x - 1; - } - else - { - xoffset = 0; - } - - if (y < 0) - { - yoffset = -y - 1; - } - else - { - yoffset = 0; - } - - /* - * Try to allocate space for room. If fails, exit - * - * Hack -- Prepare a bit larger space (+2, +2) to - * prevent generation of vaults with no-entrance. - */ - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, (POSITION)(abs(y) + 2), (POSITION)(abs(x) + 2))) return FALSE; - -#ifdef FORCE_V_IDX - v_ptr = &v_info[76 + randint1(3)]; -#endif - - msg_format_wizard(CHEAT_DUNGEON, _("大型固定Vault(%s)を生成しました。", "Greater vault (%s)."), v_name + v_ptr->name); - - /* Hack -- Build the vault */ - build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, - v_text + v_ptr->text, xoffset, yoffset, transno); - - return TRUE; -} - - -/* -* Build target vault. -* This is made by two concentric "crypts" with perpendicular -* walls creating the cross-hairs. -*/ -static void build_target_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) -{ - POSITION rad, x, y; - - /* Make a random metric */ - POSITION h1, h2, h3, h4; - h1 = randint1(32) - 16; - h2 = randint1(16); - h3 = randint1(32); - h4 = randint1(32) - 16; - - msg_print_wizard(CHEAT_DUNGEON, _("対称形ランダムVaultを生成しました。", "Elemental Vault")); - - /* work out outer radius */ - if (xsize > ysize) - { - rad = ysize / 2; - } - else - { - rad = xsize / 2; - } - - /* Make floor */ - for (x = x0 - rad; x <= x0 + rad; x++) - { - for (y = y0 - rad; y <= y0 + rad; y++) - { - /* clear room flag */ - cave[y][x].info &= ~(CAVE_ROOM); - - /* Vault - so is "icky" */ - cave[y][x].info |= CAVE_ICKY; - - if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) - { - /* inside- so is floor */ - place_floor_bold(y, x); - } - else - { - /* make granite outside so arena works */ - place_extra_bold(y, x); - } - - /* proper boundary for arena */ - if (((y + rad) == y0) || ((y - rad) == y0) || - ((x + rad) == x0) || ((x - rad) == x0)) - { - place_extra_bold(y, x); - } - } - } - - /* Find visible outer walls and set to be FEAT_OUTER */ - add_outer_wall(x0, y0, FALSE, x0 - rad - 1, y0 - rad - 1, - x0 + rad + 1, y0 + rad + 1); - - /* Add inner wall */ - for (x = x0 - rad / 2; x <= x0 + rad / 2; x++) - { - for (y = y0 - rad / 2; y <= y0 + rad / 2; y++) - { - if (dist2(y0, x0, y, x, h1, h2, h3, h4) == rad / 2) - { - /* Make an internal wall */ - place_inner_bold(y, x); - } - } - } - - /* Add perpendicular walls */ - for (x = x0 - rad; x <= x0 + rad; x++) - { - place_inner_bold(y0, x); - } - - for (y = y0 - rad; y <= y0 + rad; y++) - { - place_inner_bold(y, x0); - } - - /* Make inner vault */ - for (y = y0 - 1; y <= y0 + 1; y++) - { - place_inner_bold(y, x0 - 1); - place_inner_bold(y, x0 + 1); - } - for (x = x0 - 1; x <= x0 + 1; x++) - { - place_inner_bold(y0 - 1, x); - place_inner_bold(y0 + 1, x); - } - - place_floor_bold(y0, x0); - - - /* Add doors to vault */ - /* get two distances so can place doors relative to centre */ - x = (rad - 2) / 4 + 1; - y = rad / 2 + x; - - add_door(x0 + x, y0); - add_door(x0 + y, y0); - add_door(x0 - x, y0); - add_door(x0 - y, y0); - add_door(x0, y0 + x); - add_door(x0, y0 + y); - add_door(x0, y0 - x); - add_door(x0, y0 - y); - - /* Fill with stuff - medium difficulty */ - fill_treasure(x0 - rad, x0 + rad, y0 - rad, y0 + rad, randint1(3) + 3); -} - - -#ifdef ALLOW_CAVERNS_AND_LAKES -/* -* This routine uses a modified version of the lake code to make a -* distribution of some terrain type over the vault. This type -* depends on the dungeon depth. -* -* Miniture rooms are then scattered across the vault. -*/ -static void build_elemental_vault(POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz) -{ - int grd, roug; - int c1, c2, c3; - bool done = FALSE; - POSITION xsize, ysize, xhsize, yhsize, x, y; - int i; - int type; - - msg_print_wizard(CHEAT_DUNGEON, _("精霊界ランダムVaultを生成しました。", "Elemental Vault")); - - /* round to make sizes even */ - xhsize = xsiz / 2; - yhsize = ysiz / 2; - xsize = xhsize * 2; - ysize = yhsize * 2; - - if (dun_level < 25) - { - /* Earth vault (Rubble) */ - type = LAKE_T_EARTH_VAULT; - } - else if (dun_level < 50) - { - /* Air vault (Trees) */ - type = LAKE_T_AIR_VAULT; - } - else if (dun_level < 75) - { - /* Water vault (shallow water) */ - type = LAKE_T_WATER_VAULT; - } - else - { - /* Fire vault (shallow lava) */ - type = LAKE_T_FIRE_VAULT; - } - - while (!done) - { - /* testing values for these parameters: feel free to adjust */ - grd = 1 << (randint0(3)); - - /* want average of about 16 */ - roug = randint1(8) * randint1(4); - - /* Make up size of various componants */ - /* Floor */ - c3 = 2 * xsize / 3; - - /* Deep water/lava */ - c1 = randint0(c3 / 2) + randint0(c3 / 2) - 5; - - /* Shallow boundary */ - c2 = (c1 + c3) / 2; - - /* make it */ - generate_hmap(y0, x0, xsize, ysize, grd, roug, c3); - - /* Convert to normal format+ clean up */ - done = generate_lake(y0, x0, xsize, ysize, c1, c2, c3, type); - } - - /* Set icky flag because is a vault */ - for (x = 0; x <= xsize; x++) - { - for (y = 0; y <= ysize; y++) - { - cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY; - } - } - - /* make a few rooms in the vault */ - for (i = 1; i <= (xsize * ysize) / 50; i++) - { - build_small_room(x0 + randint0(xsize - 4) - xsize / 2 + 2, - y0 + randint0(ysize - 4) - ysize / 2 + 2); - } - - /* Fill with monsters and treasure, low difficulty */ - fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1, - y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5)); -} -#endif /* ALLOW_CAVERNS_AND_LAKES */ - - -/* Build a "mini" checkerboard vault -* -* This is done by making a permanent wall maze and setting -* the diagonal sqaures of the checker board to be granite. -* The vault has two entrances on opposite sides to guarantee -* a way to get in even if the vault abuts a side of the dungeon. -*/ -static void build_mini_c_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) -{ - POSITION dy, dx; - POSITION y1, x1, y2, x2, y, x, total; - int m, n, num_vertices; - int *visited; - - msg_print_wizard(CHEAT_DUNGEON, _("小型チェッカーランダムVaultを生成しました。", "Mini Checker Board Vault.")); - - /* Pick a random room size */ - dy = ysize / 2 - 1; - dx = xsize / 2 - 1; - - y1 = y0 - dy; - x1 = x0 - dx; - y2 = y0 + dy; - x2 = x0 + dx; - - - /* generate the room */ - for (x = x1 - 2; x <= x2 + 2; x++) - { - if (!in_bounds(y1 - 2, x)) break; - - cave[y1 - 2][x].info |= (CAVE_ROOM | CAVE_ICKY); - - place_outer_noperm_bold(y1 - 2, x); - } - - for (x = x1 - 2; x <= x2 + 2; x++) - { - if (!in_bounds(y2 + 2, x)) break; - - cave[y2 + 2][x].info |= (CAVE_ROOM | CAVE_ICKY); - - place_outer_noperm_bold(y2 + 2, x); - } - - for (y = y1 - 2; y <= y2 + 2; y++) - { - if (!in_bounds(y, x1 - 2)) break; - - cave[y][x1 - 2].info |= (CAVE_ROOM | CAVE_ICKY); - - place_outer_noperm_bold(y, x1 - 2); - } - - for (y = y1 - 2; y <= y2 + 2; y++) - { - if (!in_bounds(y, x2 + 2)) break; - - cave[y][x2 + 2].info |= (CAVE_ROOM | CAVE_ICKY); - - place_outer_noperm_bold(y, x2 + 2); - } - - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - cave_type *c_ptr = &cave[y][x]; - - c_ptr->info |= (CAVE_ROOM | CAVE_ICKY); - - /* Permanent walls */ - place_inner_perm_grid(c_ptr); - } - } - - - /* dimensions of vertex array */ - m = dx + 1; - n = dy + 1; - num_vertices = m * n; - - /* initialize array of visited vertices */ - C_MAKE(visited, num_vertices, int); - - /* traverse the graph to create a spannng tree, pick a random root */ - r_visit(y1, x1, y2, x2, randint0(num_vertices), 0, visited); - - /* Make it look like a checker board vault */ - for (x = x1; x <= x2; x++) - { - for (y = y1; y <= y2; y++) - { - total = x - x1 + y - y1; - /* If total is odd- and is a floor then make a wall */ - if ((total % 2 == 1) && is_floor_bold(y, x)) - { - place_inner_bold(y, x); - } - } - } - - /* Make a couple of entrances */ - if (one_in_(2)) - { - /* left and right */ - y = randint1(dy) + dy / 2; - place_inner_bold(y1 + y, x1 - 1); - place_inner_bold(y1 + y, x2 + 1); - } - else - { - /* top and bottom */ - x = randint1(dx) + dx / 2; - place_inner_bold(y1 - 1, x1 + x); - place_inner_bold(y2 + 1, x1 + x); - } - - /* Fill with monsters and treasure, highest difficulty */ - fill_treasure(x1, x2, y1, y2, 10); - - C_KILL(visited, num_vertices, int); -} - -/* Build a castle */ -/* Driver routine: clear the region and call the recursive -* room routine. -* -*This makes a vault that looks like a castle/ city in the dungeon. -*/ -static void build_castle_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) -{ - POSITION dy, dx; - POSITION y1, x1, y2, x2; - POSITION y, x; - - /* Pick a random room size */ - dy = ysize / 2 - 1; - dx = xsize / 2 - 1; - - y1 = y0 - dy; - x1 = x0 - dx; - y2 = y0 + dy; - x2 = x0 + dx; - - msg_print_wizard(CHEAT_DUNGEON, _("城型ランダムVaultを生成しました。", "Castle Vault")); - - /* generate the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY); - /* Make everything a floor */ - place_floor_bold(y, x); - } - } - - /* Make the castle */ - build_recursive_room(x1, y1, x2, y2, randint1(5)); - - /* Fill with monsters and treasure, low difficulty */ - fill_treasure(x1, x2, y1, y2, randint1(3)); -} - - - -/*! -* @brief タイプ10の部屋…ランダム生成vault / Type 10 -- Random vaults -* @return なし -*/ -bool build_type10(void) -{ - POSITION y0, x0, xsize, ysize, vtype; - - /* big enough to look good, small enough to be fairly common. */ - xsize = randint1(22) + 22; - ysize = randint1(11) + 11; - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) return FALSE; - - /* Select type of vault */ -#ifdef ALLOW_CAVERNS_AND_LAKES - do - { - vtype = randint1(15); - } while ((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) && - ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11))); -#else /* ALLOW_CAVERNS_AND_LAKES */ - do - { - vtype = randint1(7); - } while ((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) && - ((vtype == 1) || (vtype == 3))); -#endif /* ALLOW_CAVERNS_AND_LAKES */ - - switch (vtype) - { - /* Build an appropriate room */ - case 1: case 9: build_bubble_vault(x0, y0, xsize, ysize); break; - case 2: case 10: build_room_vault(x0, y0, xsize, ysize); break; - case 3: case 11: build_cave_vault(x0, y0, xsize, ysize); break; - case 4: case 12: build_maze_vault(x0, y0, xsize, ysize, TRUE); break; - case 5: case 13: build_mini_c_vault(x0, y0, xsize, ysize); break; - case 6: case 14: build_castle_vault(x0, y0, xsize, ysize); break; - case 7: case 15: build_target_vault(x0, y0, xsize, ysize); break; -#ifdef ALLOW_CAVERNS_AND_LAKES - case 8: build_elemental_vault(x0, y0, xsize, ysize); break; -#endif /* ALLOW_CAVERNS_AND_LAKES */ - /* I know how to add a few more... give me some time. */ - - /* Paranoia */ - default: return FALSE; - } - - return TRUE; -} - - -/*! -* @brief タイプ17の部屋…v_info.txtより固定特殊部屋を生成する / Type 17 -- fixed special room (see "v_info.txt") -* @return なし -*/ -bool build_type17(void) -{ - vault_type *v_ptr = NULL; - int dummy; - POSITION x, y; - POSITION xval, yval; - POSITION xoffset, yoffset; - int transno; - - /* Pick a lesser vault */ - for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) - { - /* Access a random vault record */ - v_ptr = &v_info[randint0(max_v_idx)]; - - /* Accept the special fix room. */ - if (v_ptr->typ == 17) break; - } - - /* No lesser vault found */ - if (dummy >= SAFE_MAX_ATTEMPTS) - { - msg_print_wizard(CHEAT_DUNGEON, _("固定特殊部屋を配置できませんでした。", "Could not place fixed special room.")); - return FALSE; - } - - /* pick type of transformation (0-7) */ - transno = randint0(8); - - /* calculate offsets */ - x = v_ptr->wid; - y = v_ptr->hgt; - - /* Some huge vault cannot be ratated to fit in the dungeon */ - if (x + 2 > cur_hgt - 2) - { - /* Forbid 90 or 270 degree ratation */ - transno &= ~1; - } - - coord_trans(&x, &y, 0, 0, transno); - - if (x < 0) - { - xoffset = -x - 1; - } - else - { - xoffset = 0; - } - - if (y < 0) - { - yoffset = -y - 1; - } - else - { - yoffset = 0; - } - - /* Find and reserve some space in the dungeon. Get center of room. */ - if (!find_space(&yval, &xval, abs(y), abs(x))) return FALSE; - -#ifdef FORCE_V_IDX - v_ptr = &v_info[2]; -#endif - - msg_format_wizard(CHEAT_DUNGEON, _("特殊固定部屋(%s)を生成しました。", "Special Fix room (%s)."), v_name + v_ptr->name); - - /* Hack -- Build the vault */ - build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, - v_text + v_ptr->text, xoffset, yoffset, transno); - - return TRUE; -} - +#include "angband.h" +#include "generate.h" +#include "grid.h" +#include "rooms.h" +#include "store.h" +#include "trap.h" +#include "monster.h" + +/* +* This function creates a random vault that looks like a collection of bubbles. +* It works by getting a set of coordinates that represent the center of each +* bubble. The entire room is made by seeing which bubble center is closest. If +* two centers are equidistant then the square is a wall, otherwise it is a floor. +* The only exception is for squares really near a center, these are always floor. +* (It looks better than without this check.) +* +* Note: If two centers are on the same point then this algorithm will create a +* blank bubble filled with walls. - This is prevented from happening. +*/ +static void build_bubble_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) +{ +#define BUBBLENUM 10 /* number of bubbles */ + + /* array of center points of bubbles */ + coord center[BUBBLENUM]; + + int i, j; + POSITION x = 0, y = 0; + u16b min1, min2, temp; + bool done; + + /* Offset from center to top left hand corner */ + POSITION xhsize = xsize / 2; + POSITION yhsize = ysize / 2; + + msg_print_wizard(CHEAT_DUNGEON, _("泡型ランダムVaultを生成しました。", "Room Vault.")); + + /* Allocate center of bubbles */ + center[0].x = (byte)randint1(xsize - 3) + 1; + center[0].y = (byte)randint1(ysize - 3) + 1; + + for (i = 1; i < BUBBLENUM; i++) + { + done = FALSE; + + /* get center and check to see if it is unique */ + while (!done) + { + done = TRUE; + + x = randint1(xsize - 3) + 1; + y = randint1(ysize - 3) + 1; + + for (j = 0; j < i; j++) + { + /* rough test to see if there is an overlap */ + if ((x == center[j].x) && (y == center[j].y)) done = FALSE; + } + } + + center[i].x = x; + center[i].y = y; + } + + + /* Top and bottom boundaries */ + for (i = 0; i < xsize; i++) + { + int side_x = x0 - xhsize + i; + + place_outer_noperm_bold(y0 - yhsize + 0, side_x); + cave[y0 - yhsize + 0][side_x].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(y0 - yhsize + ysize - 1, side_x); + cave[y0 - yhsize + ysize - 1][side_x].info |= (CAVE_ROOM | CAVE_ICKY); + } + + /* Left and right boundaries */ + for (i = 1; i < ysize - 1; i++) + { + int side_y = y0 - yhsize + i; + + place_outer_noperm_bold(side_y, x0 - xhsize + 0); + cave[side_y][x0 - xhsize + 0].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(side_y, x0 - xhsize + xsize - 1); + cave[side_y][x0 - xhsize + xsize - 1].info |= (CAVE_ROOM | CAVE_ICKY); + } + + /* Fill in middle with bubbles */ + for (x = 1; x < xsize - 1; x++) + { + for (y = 1; y < ysize - 1; y++) + { + /* Get distances to two closest centers */ + + min1 = (u16b)distance(x, y, center[0].x, center[0].y); + min2 = (u16b)distance(x, y, center[1].x, center[1].y); + + if (min1 > min2) + { + /* swap if in wrong order */ + temp = min1; + min1 = min2; + min2 = temp; + } + + /* Scan the rest */ + for (i = 2; i < BUBBLENUM; i++) + { + temp = (u16b)distance(x, y, center[i].x, center[i].y); + + if (temp < min1) + { + /* smallest */ + min2 = min1; + min1 = temp; + } + else if (temp < min2) + { + /* second smallest */ + min2 = temp; + } + } + if (((min2 - min1) <= 2) && (!(min1 < 3))) + { + /* Boundary at midpoint+ not at inner region of bubble */ + place_outer_noperm_bold(y0 - yhsize + y, x0 - xhsize + x); + } + else + { + /* middle of a bubble */ + place_floor_bold(y0 - yhsize + y, x0 - xhsize + x); + } + + /* clean up rest of flags */ + cave[y0 - yhsize + y][x0 - xhsize + x].info |= (CAVE_ROOM | CAVE_ICKY); + } + } + + /* Try to add some random doors */ + for (i = 0; i < 500; i++) + { + x = randint1(xsize - 3) - xhsize + x0 + 1; + y = randint1(ysize - 3) - yhsize + y0 + 1; + add_door(x, y); + } + + /* Fill with monsters and treasure, low difficulty */ + fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5)); +} + +/* Create a random vault that looks like a collection of overlapping rooms */ +static void build_room_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) +{ + POSITION x1, x2, y1, y2, xhsize, yhsize; + int i; + + /* get offset from center */ + xhsize = xsize / 2; + yhsize = ysize / 2; + + msg_print_wizard(CHEAT_DUNGEON, _("部屋型ランダムVaultを生成しました。", "Room Vault.")); + + /* fill area so don't get problems with arena levels */ + for (x1 = 0; x1 < xsize; x1++) + { + POSITION x = x0 - xhsize + x1; + + for (y1 = 0; y1 < ysize; y1++) + { + POSITION y = y0 - yhsize + y1; + + place_extra_bold(y, x); + cave[y][x].info &= (~CAVE_ICKY); + } + } + + /* add ten random rooms */ + for (i = 0; i < 10; i++) + { + x1 = randint1(xhsize) * 2 + x0 - xhsize; + x2 = randint1(xhsize) * 2 + x0 - xhsize; + y1 = randint1(yhsize) * 2 + y0 - yhsize; + y2 = randint1(yhsize) * 2 + y0 - yhsize; + build_room(x1, x2, y1, y2); + } + + /* Add some random doors */ + for (i = 0; i < 500; i++) + { + x1 = randint1(xsize - 3) - xhsize + x0 + 1; + y1 = randint1(ysize - 3) - yhsize + y0 + 1; + add_door(x1, y1); + } + + /* Fill with monsters and treasure, high difficulty */ + fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5) + 5); +} + + +/* Create a random vault out of a fractal cave */ +static void build_cave_vault(POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz) +{ + int grd, roug, cutoff; + bool done, light, room; + POSITION xhsize, yhsize, xsize, ysize, x, y; + + /* round to make sizes even */ + xhsize = xsiz / 2; + yhsize = ysiz / 2; + xsize = xhsize * 2; + ysize = yhsize * 2; + + msg_print_wizard(CHEAT_DUNGEON, _("洞穴ランダムVaultを生成しました。", "Cave Vault.")); + + light = done = FALSE; + room = TRUE; + + while (!done) + { + /* testing values for these parameters feel free to adjust */ + grd = 1 << randint0(4); + + /* want average of about 16 */ + roug = randint1(8) * randint1(4); + + /* about size/2 */ + cutoff = randint1(xsize / 4) + randint1(ysize / 4) + + randint1(xsize / 4) + randint1(ysize / 4); + + /* make it */ + generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff); + + /* Convert to normal format+ clean up */ + done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room); + } + + /* Set icky flag because is a vault */ + for (x = 0; x <= xsize; x++) + { + for (y = 0; y <= ysize; y++) + { + cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY; + } + } + + /* Fill with monsters and treasure, low difficulty */ + fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1, y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5)); +} + + + +/*! +* @brief Vault地形を回転、上下左右反転するための座標変換を返す / coordinate translation code +* @param x 変換したい点のX座標参照ポインタ +* @param y 変換したい点のY座標参照ポインタ +* @param xoffset Vault生成時の基準X座標 +* @param yoffset Vault生成時の基準Y座標 +* @param transno 処理ID +* @return なし +*/ +static void coord_trans(POSITION *x, POSITION *y, POSITION xoffset, POSITION yoffset, int transno) +{ + int i; + int temp; + + /* + * transno specifies what transformation is required. (0-7) + * The lower two bits indicate by how much the vault is rotated, + * and the upper bit indicates a reflection. + * This is done by using rotation matrices... however since + * these are mostly zeros for rotations by 90 degrees this can + * be expressed simply in terms of swapping and inverting the + * x and y coordinates. + */ + for (i = 0; i < transno % 4; i++) + { + /* rotate by 90 degrees */ + temp = *x; + *x = -(*y); + *y = temp; + } + + if (transno / 4) + { + /* Reflect depending on status of 3rd bit. */ + *x = -(*x); + } + + /* Add offsets so vault stays in the first quadrant */ + *x += xoffset; + *y += yoffset; +} + + +/*! +* @brief Vaultをフロアに配置する / Hack -- fill in "vault" rooms +* @param yval 生成基準Y座標 +* @param xval 生成基準X座標 +* @param ymax VaultのYサイズ +* @param xmax VaultのXサイズ +* @param data Vaultのデータ文字列 +* @param xoffset 変換基準X座標 +* @param yoffset 変換基準Y座標 +* @param transno 変換ID +* @return なし +*/ +static void build_vault(POSITION yval, POSITION xval, POSITION ymax, POSITION xmax, concptr data, + POSITION xoffset, POSITION yoffset, int transno) +{ + POSITION dx, dy, x, y, i, j; + concptr t; + cave_type *c_ptr; + + /* Place dungeon features and objects */ + for (t = data, dy = 0; dy < ymax; dy++) + { + for (dx = 0; dx < xmax; dx++, t++) + { + /* prevent loop counter from being overwritten */ + i = dx; + j = dy; + + /* Flip / rotate */ + coord_trans(&i, &j, xoffset, yoffset, transno); + + /* Extract the location */ + if (transno % 2 == 0) + { + /* no swap of x/y */ + x = xval - (xmax / 2) + i; + y = yval - (ymax / 2) + j; + } + else + { + /* swap of x/y */ + x = xval - (ymax / 2) + i; + y = yval - (xmax / 2) + j; + } + + /* Hack -- skip "non-grids" */ + if (*t == ' ') continue; + c_ptr = &cave[y][x]; + + /* Lay down a floor */ + place_floor_grid(c_ptr); + + /* Remove any mimic */ + c_ptr->mimic = 0; + + /* Part of a vault */ + c_ptr->info |= (CAVE_ROOM | CAVE_ICKY); + + /* Analyze the grid */ + switch (*t) + { + /* Granite wall (outer) */ + case '%': + place_outer_noperm_grid(c_ptr); + break; + + /* Granite wall (inner) */ + case '#': + place_inner_grid(c_ptr); + break; + + /* Glass wall (inner) */ + case '$': + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + break; + + /* Permanent wall (inner) */ + case 'X': + place_inner_perm_grid(c_ptr); + break; + + /* Permanent glass wall (inner) */ + case 'Y': + place_inner_perm_grid(c_ptr); + c_ptr->feat = feat_permanent_glass_wall; + break; + + /* Treasure/trap */ + case '*': + if (randint0(100) < 75) + { + place_object(y, x, 0L); + } + else + { + place_trap(y, x); + } + break; + + /* Treasure */ + case '[': + place_object(y, x, 0L); + break; + + /* Tree */ + case ':': + c_ptr->feat = feat_tree; + break; + + /* Secret doors */ + case '+': + place_secret_door(y, x, DOOR_DEFAULT); + break; + + /* Secret glass doors */ + case '-': + place_secret_door(y, x, DOOR_GLASS_DOOR); + if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; + break; + + /* Curtains */ + case '\'': + place_secret_door(y, x, DOOR_CURTAIN); + break; + + /* Trap */ + case '^': + place_trap(y, x); + break; + + /* Black market in a dungeon */ + case 'S': + set_cave_feat(y, x, feat_black_market); + store_init(NO_TOWN, STORE_BLACK); + break; + + /* The Pattern */ + case 'p': + set_cave_feat(y, x, feat_pattern_start); + break; + + case 'a': + set_cave_feat(y, x, feat_pattern_1); + break; + + case 'b': + set_cave_feat(y, x, feat_pattern_2); + break; + + case 'c': + set_cave_feat(y, x, feat_pattern_3); + break; + + case 'd': + set_cave_feat(y, x, feat_pattern_4); + break; + + case 'P': + set_cave_feat(y, x, feat_pattern_end); + break; + + case 'B': + set_cave_feat(y, x, feat_pattern_exit); + break; + + case 'A': + /* Reward for Pattern walk */ + object_level = base_level + 12; + place_object(y, x, AM_GOOD | AM_GREAT); + object_level = base_level; + break; + + case '~': + set_cave_feat(y, x, feat_shallow_water); + break; + + case '=': + set_cave_feat(y, x, feat_deep_water); + break; + + case 'v': + set_cave_feat(y, x, feat_shallow_lava); + break; + + case 'w': + set_cave_feat(y, x, feat_deep_lava); + break; + + case 'f': + set_cave_feat(y, x, feat_shallow_acid_puddle); + break; + + case 'F': + set_cave_feat(y, x, feat_deep_acid_puddle); + break; + + case 'g': + set_cave_feat(y, x, feat_shallow_poisonous_puddle); + break; + + case 'G': + set_cave_feat(y, x, feat_deep_poisonous_puddle); + break; + + case 'h': + set_cave_feat(y, x, feat_cold_zone); + break; + + case 'H': + set_cave_feat(y, x, feat_heavy_cold_zone); + break; + + case 'i': + set_cave_feat(y, x, feat_electrical_zone); + break; + + case 'I': + set_cave_feat(y, x, feat_heavy_electrical_zone); + break; + + } + } + } + + + /* Place dungeon monsters and objects */ + for (t = data, dy = 0; dy < ymax; dy++) + { + for (dx = 0; dx < xmax; dx++, t++) + { + /* prevent loop counter from being overwritten */ + i = dx; + j = dy; + + /* Flip / rotate */ + coord_trans(&i, &j, xoffset, yoffset, transno); + + /* Extract the location */ + if (transno % 2 == 0) + { + /* no swap of x/y */ + x = xval - (xmax / 2) + i; + y = yval - (ymax / 2) + j; + } + else + { + /* swap of x/y */ + x = xval - (ymax / 2) + i; + y = yval - (xmax / 2) + j; + } + + /* Hack -- skip "non-grids" */ + if (*t == ' ') continue; + + /* Analyze the symbol */ + switch (*t) + { + /* Monster */ + case '&': + { + monster_level = base_level + 5; + place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); + monster_level = base_level; + break; + } + + /* Meaner monster */ + case '@': + { + monster_level = base_level + 11; + place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); + monster_level = base_level; + break; + } + + /* Meaner monster, plus treasure */ + case '9': + { + monster_level = base_level + 9; + place_monster(y, x, PM_ALLOW_SLEEP); + monster_level = base_level; + object_level = base_level + 7; + place_object(y, x, AM_GOOD); + object_level = base_level; + break; + } + + /* Nasty monster and treasure */ + case '8': + { + monster_level = base_level + 40; + place_monster(y, x, PM_ALLOW_SLEEP); + monster_level = base_level; + object_level = base_level + 20; + place_object(y, x, AM_GOOD | AM_GREAT); + object_level = base_level; + break; + } + + /* Monster and/or object */ + case ',': + { + if (randint0(100) < 50) + { + monster_level = base_level + 3; + place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); + monster_level = base_level; + } + if (randint0(100) < 50) + { + object_level = base_level + 7; + place_object(y, x, 0L); + object_level = base_level; + } + break; + } + + } + } + } +} + + + +/*! +* @brief タイプ7の部屋…v_info.txtより小型vaultを生成する / Type 7 -- simple vaults (see "v_info.txt") +* @return なし +*/ +bool build_type7(void) +{ + vault_type *v_ptr = NULL; + int dummy; + POSITION x, y; + POSITION xval, yval; + POSITION xoffset, yoffset; + int transno; + + /* Pick a lesser vault */ + for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) + { + /* Access a random vault record */ + v_ptr = &v_info[randint0(max_v_idx)]; + + /* Accept the first lesser vault */ + if (v_ptr->typ == 7) break; + } + + /* No lesser vault found */ + if (dummy >= SAFE_MAX_ATTEMPTS) + { + msg_print_wizard(CHEAT_DUNGEON, _("小型固定Vaultを配置できませんでした。", "Could not place lesser vault.")); + return FALSE; + } + + /* pick type of transformation (0-7) */ + transno = randint0(8); + + /* calculate offsets */ + x = v_ptr->wid; + y = v_ptr->hgt; + + /* Some huge vault cannot be ratated to fit in the dungeon */ + if (x + 2 > cur_hgt - 2) + { + /* Forbid 90 or 270 degree ratation */ + transno &= ~1; + } + + coord_trans(&x, &y, 0, 0, transno); + + if (x < 0) + { + xoffset = -x - 1; + } + else + { + xoffset = 0; + } + + if (y < 0) + { + yoffset = -y - 1; + } + else + { + yoffset = 0; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, abs(y), abs(x))) return FALSE; + +#ifdef FORCE_V_IDX + v_ptr = &v_info[2]; +#endif + + msg_format_wizard(CHEAT_DUNGEON, _("小型Vault(%s)を生成しました。", "Lesser vault (%s)."), v_name + v_ptr->name); + + /* Hack -- Build the vault */ + build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, + v_text + v_ptr->text, xoffset, yoffset, transno); + + return TRUE; +} + +/*! +* @brief タイプ8の部屋…v_info.txtより大型vaultを生成する / Type 8 -- greater vaults (see "v_info.txt") +* @return なし +*/ +bool build_type8(void) +{ + vault_type *v_ptr; + int dummy; + POSITION xval, yval; + POSITION x, y; + int transno; + POSITION xoffset, yoffset; + + /* Pick a greater vault */ + for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) + { + /* Access a random vault record */ + v_ptr = &v_info[randint0(max_v_idx)]; + + /* Accept the first greater vault */ + if (v_ptr->typ == 8) break; + } + + /* No greater vault found */ + if (dummy >= SAFE_MAX_ATTEMPTS) + { + msg_print_wizard(CHEAT_DUNGEON, _("大型固定Vaultを配置できませんでした。", "Could not place greater vault.")); + return FALSE; + } + + /* pick type of transformation (0-7) */ + transno = randint0(8); + + /* calculate offsets */ + x = v_ptr->wid; + y = v_ptr->hgt; + + /* Some huge vault cannot be ratated to fit in the dungeon */ + if (x + 2 > cur_hgt - 2) + { + /* Forbid 90 or 270 degree ratation */ + transno &= ~1; + } + + coord_trans(&x, &y, 0, 0, transno); + + if (x < 0) + { + xoffset = -x - 1; + } + else + { + xoffset = 0; + } + + if (y < 0) + { + yoffset = -y - 1; + } + else + { + yoffset = 0; + } + + /* + * Try to allocate space for room. If fails, exit + * + * Hack -- Prepare a bit larger space (+2, +2) to + * prevent generation of vaults with no-entrance. + */ + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, (POSITION)(abs(y) + 2), (POSITION)(abs(x) + 2))) return FALSE; + +#ifdef FORCE_V_IDX + v_ptr = &v_info[76 + randint1(3)]; +#endif + + msg_format_wizard(CHEAT_DUNGEON, _("大型固定Vault(%s)を生成しました。", "Greater vault (%s)."), v_name + v_ptr->name); + + /* Hack -- Build the vault */ + build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, + v_text + v_ptr->text, xoffset, yoffset, transno); + + return TRUE; +} + + +/* +* Build target vault. +* This is made by two concentric "crypts" with perpendicular +* walls creating the cross-hairs. +*/ +static void build_target_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) +{ + POSITION rad, x, y; + + /* Make a random metric */ + POSITION h1, h2, h3, h4; + h1 = randint1(32) - 16; + h2 = randint1(16); + h3 = randint1(32); + h4 = randint1(32) - 16; + + msg_print_wizard(CHEAT_DUNGEON, _("対称形ランダムVaultを生成しました。", "Elemental Vault")); + + /* work out outer radius */ + if (xsize > ysize) + { + rad = ysize / 2; + } + else + { + rad = xsize / 2; + } + + /* Make floor */ + for (x = x0 - rad; x <= x0 + rad; x++) + { + for (y = y0 - rad; y <= y0 + rad; y++) + { + /* clear room flag */ + cave[y][x].info &= ~(CAVE_ROOM); + + /* Vault - so is "icky" */ + cave[y][x].info |= CAVE_ICKY; + + if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) + { + /* inside- so is floor */ + place_floor_bold(y, x); + } + else + { + /* make granite outside so arena works */ + place_extra_bold(y, x); + } + + /* proper boundary for arena */ + if (((y + rad) == y0) || ((y - rad) == y0) || + ((x + rad) == x0) || ((x - rad) == x0)) + { + place_extra_bold(y, x); + } + } + } + + /* Find visible outer walls and set to be FEAT_OUTER */ + add_outer_wall(x0, y0, FALSE, x0 - rad - 1, y0 - rad - 1, + x0 + rad + 1, y0 + rad + 1); + + /* Add inner wall */ + for (x = x0 - rad / 2; x <= x0 + rad / 2; x++) + { + for (y = y0 - rad / 2; y <= y0 + rad / 2; y++) + { + if (dist2(y0, x0, y, x, h1, h2, h3, h4) == rad / 2) + { + /* Make an internal wall */ + place_inner_bold(y, x); + } + } + } + + /* Add perpendicular walls */ + for (x = x0 - rad; x <= x0 + rad; x++) + { + place_inner_bold(y0, x); + } + + for (y = y0 - rad; y <= y0 + rad; y++) + { + place_inner_bold(y, x0); + } + + /* Make inner vault */ + for (y = y0 - 1; y <= y0 + 1; y++) + { + place_inner_bold(y, x0 - 1); + place_inner_bold(y, x0 + 1); + } + for (x = x0 - 1; x <= x0 + 1; x++) + { + place_inner_bold(y0 - 1, x); + place_inner_bold(y0 + 1, x); + } + + place_floor_bold(y0, x0); + + + /* Add doors to vault */ + /* get two distances so can place doors relative to centre */ + x = (rad - 2) / 4 + 1; + y = rad / 2 + x; + + add_door(x0 + x, y0); + add_door(x0 + y, y0); + add_door(x0 - x, y0); + add_door(x0 - y, y0); + add_door(x0, y0 + x); + add_door(x0, y0 + y); + add_door(x0, y0 - x); + add_door(x0, y0 - y); + + /* Fill with stuff - medium difficulty */ + fill_treasure(x0 - rad, x0 + rad, y0 - rad, y0 + rad, randint1(3) + 3); +} + + +#ifdef ALLOW_CAVERNS_AND_LAKES +/* +* This routine uses a modified version of the lake code to make a +* distribution of some terrain type over the vault. This type +* depends on the dungeon depth. +* +* Miniture rooms are then scattered across the vault. +*/ +static void build_elemental_vault(POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz) +{ + int grd, roug; + int c1, c2, c3; + bool done = FALSE; + POSITION xsize, ysize, xhsize, yhsize, x, y; + int i; + int type; + + msg_print_wizard(CHEAT_DUNGEON, _("精霊界ランダムVaultを生成しました。", "Elemental Vault")); + + /* round to make sizes even */ + xhsize = xsiz / 2; + yhsize = ysiz / 2; + xsize = xhsize * 2; + ysize = yhsize * 2; + + if (dun_level < 25) + { + /* Earth vault (Rubble) */ + type = LAKE_T_EARTH_VAULT; + } + else if (dun_level < 50) + { + /* Air vault (Trees) */ + type = LAKE_T_AIR_VAULT; + } + else if (dun_level < 75) + { + /* Water vault (shallow water) */ + type = LAKE_T_WATER_VAULT; + } + else + { + /* Fire vault (shallow lava) */ + type = LAKE_T_FIRE_VAULT; + } + + while (!done) + { + /* testing values for these parameters: feel free to adjust */ + grd = 1 << (randint0(3)); + + /* want average of about 16 */ + roug = randint1(8) * randint1(4); + + /* Make up size of various componants */ + /* Floor */ + c3 = 2 * xsize / 3; + + /* Deep water/lava */ + c1 = randint0(c3 / 2) + randint0(c3 / 2) - 5; + + /* Shallow boundary */ + c2 = (c1 + c3) / 2; + + /* make it */ + generate_hmap(y0, x0, xsize, ysize, grd, roug, c3); + + /* Convert to normal format+ clean up */ + done = generate_lake(y0, x0, xsize, ysize, c1, c2, c3, type); + } + + /* Set icky flag because is a vault */ + for (x = 0; x <= xsize; x++) + { + for (y = 0; y <= ysize; y++) + { + cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY; + } + } + + /* make a few rooms in the vault */ + for (i = 1; i <= (xsize * ysize) / 50; i++) + { + build_small_room(x0 + randint0(xsize - 4) - xsize / 2 + 2, + y0 + randint0(ysize - 4) - ysize / 2 + 2); + } + + /* Fill with monsters and treasure, low difficulty */ + fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1, + y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5)); +} +#endif /* ALLOW_CAVERNS_AND_LAKES */ + + +/* Build a "mini" checkerboard vault +* +* This is done by making a permanent wall maze and setting +* the diagonal sqaures of the checker board to be granite. +* The vault has two entrances on opposite sides to guarantee +* a way to get in even if the vault abuts a side of the dungeon. +*/ +static void build_mini_c_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) +{ + POSITION dy, dx; + POSITION y1, x1, y2, x2, y, x, total; + int m, n, num_vertices; + int *visited; + + msg_print_wizard(CHEAT_DUNGEON, _("小型チェッカーランダムVaultを生成しました。", "Mini Checker Board Vault.")); + + /* Pick a random room size */ + dy = ysize / 2 - 1; + dx = xsize / 2 - 1; + + y1 = y0 - dy; + x1 = x0 - dx; + y2 = y0 + dy; + x2 = x0 + dx; + + + /* generate the room */ + for (x = x1 - 2; x <= x2 + 2; x++) + { + if (!in_bounds(y1 - 2, x)) break; + + cave[y1 - 2][x].info |= (CAVE_ROOM | CAVE_ICKY); + + place_outer_noperm_bold(y1 - 2, x); + } + + for (x = x1 - 2; x <= x2 + 2; x++) + { + if (!in_bounds(y2 + 2, x)) break; + + cave[y2 + 2][x].info |= (CAVE_ROOM | CAVE_ICKY); + + place_outer_noperm_bold(y2 + 2, x); + } + + for (y = y1 - 2; y <= y2 + 2; y++) + { + if (!in_bounds(y, x1 - 2)) break; + + cave[y][x1 - 2].info |= (CAVE_ROOM | CAVE_ICKY); + + place_outer_noperm_bold(y, x1 - 2); + } + + for (y = y1 - 2; y <= y2 + 2; y++) + { + if (!in_bounds(y, x2 + 2)) break; + + cave[y][x2 + 2].info |= (CAVE_ROOM | CAVE_ICKY); + + place_outer_noperm_bold(y, x2 + 2); + } + + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + cave_type *c_ptr = &cave[y][x]; + + c_ptr->info |= (CAVE_ROOM | CAVE_ICKY); + + /* Permanent walls */ + place_inner_perm_grid(c_ptr); + } + } + + + /* dimensions of vertex array */ + m = dx + 1; + n = dy + 1; + num_vertices = m * n; + + /* initialize array of visited vertices */ + C_MAKE(visited, num_vertices, int); + + /* traverse the graph to create a spannng tree, pick a random root */ + r_visit(y1, x1, y2, x2, randint0(num_vertices), 0, visited); + + /* Make it look like a checker board vault */ + for (x = x1; x <= x2; x++) + { + for (y = y1; y <= y2; y++) + { + total = x - x1 + y - y1; + /* If total is odd- and is a floor then make a wall */ + if ((total % 2 == 1) && is_floor_bold(y, x)) + { + place_inner_bold(y, x); + } + } + } + + /* Make a couple of entrances */ + if (one_in_(2)) + { + /* left and right */ + y = randint1(dy) + dy / 2; + place_inner_bold(y1 + y, x1 - 1); + place_inner_bold(y1 + y, x2 + 1); + } + else + { + /* top and bottom */ + x = randint1(dx) + dx / 2; + place_inner_bold(y1 - 1, x1 + x); + place_inner_bold(y2 + 1, x1 + x); + } + + /* Fill with monsters and treasure, highest difficulty */ + fill_treasure(x1, x2, y1, y2, 10); + + C_KILL(visited, num_vertices, int); +} + +/* Build a castle */ +/* Driver routine: clear the region and call the recursive +* room routine. +* +*This makes a vault that looks like a castle/ city in the dungeon. +*/ +static void build_castle_vault(POSITION x0, POSITION y0, POSITION xsize, POSITION ysize) +{ + POSITION dy, dx; + POSITION y1, x1, y2, x2; + POSITION y, x; + + /* Pick a random room size */ + dy = ysize / 2 - 1; + dx = xsize / 2 - 1; + + y1 = y0 - dy; + x1 = x0 - dx; + y2 = y0 + dy; + x2 = x0 + dx; + + msg_print_wizard(CHEAT_DUNGEON, _("城型ランダムVaultを生成しました。", "Castle Vault")); + + /* generate the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY); + /* Make everything a floor */ + place_floor_bold(y, x); + } + } + + /* Make the castle */ + build_recursive_room(x1, y1, x2, y2, randint1(5)); + + /* Fill with monsters and treasure, low difficulty */ + fill_treasure(x1, x2, y1, y2, randint1(3)); +} + + + +/*! +* @brief タイプ10の部屋…ランダム生成vault / Type 10 -- Random vaults +* @return なし +*/ +bool build_type10(void) +{ + POSITION y0, x0, xsize, ysize, vtype; + + /* big enough to look good, small enough to be fairly common. */ + xsize = randint1(22) + 22; + ysize = randint1(11) + 11; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) return FALSE; + + /* Select type of vault */ +#ifdef ALLOW_CAVERNS_AND_LAKES + do + { + vtype = randint1(15); + } while ((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) && + ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11))); +#else /* ALLOW_CAVERNS_AND_LAKES */ + do + { + vtype = randint1(7); + } while ((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) && + ((vtype == 1) || (vtype == 3))); +#endif /* ALLOW_CAVERNS_AND_LAKES */ + + switch (vtype) + { + /* Build an appropriate room */ + case 1: case 9: build_bubble_vault(x0, y0, xsize, ysize); break; + case 2: case 10: build_room_vault(x0, y0, xsize, ysize); break; + case 3: case 11: build_cave_vault(x0, y0, xsize, ysize); break; + case 4: case 12: build_maze_vault(x0, y0, xsize, ysize, TRUE); break; + case 5: case 13: build_mini_c_vault(x0, y0, xsize, ysize); break; + case 6: case 14: build_castle_vault(x0, y0, xsize, ysize); break; + case 7: case 15: build_target_vault(x0, y0, xsize, ysize); break; +#ifdef ALLOW_CAVERNS_AND_LAKES + case 8: build_elemental_vault(x0, y0, xsize, ysize); break; +#endif /* ALLOW_CAVERNS_AND_LAKES */ + /* I know how to add a few more... give me some time. */ + + /* Paranoia */ + default: return FALSE; + } + + return TRUE; +} + + +/*! +* @brief タイプ17の部屋…v_info.txtより固定特殊部屋を生成する / Type 17 -- fixed special room (see "v_info.txt") +* @return なし +*/ +bool build_type17(void) +{ + vault_type *v_ptr = NULL; + int dummy; + POSITION x, y; + POSITION xval, yval; + POSITION xoffset, yoffset; + int transno; + + /* Pick a lesser vault */ + for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) + { + /* Access a random vault record */ + v_ptr = &v_info[randint0(max_v_idx)]; + + /* Accept the special fix room. */ + if (v_ptr->typ == 17) break; + } + + /* No lesser vault found */ + if (dummy >= SAFE_MAX_ATTEMPTS) + { + msg_print_wizard(CHEAT_DUNGEON, _("固定特殊部屋を配置できませんでした。", "Could not place fixed special room.")); + return FALSE; + } + + /* pick type of transformation (0-7) */ + transno = randint0(8); + + /* calculate offsets */ + x = v_ptr->wid; + y = v_ptr->hgt; + + /* Some huge vault cannot be ratated to fit in the dungeon */ + if (x + 2 > cur_hgt - 2) + { + /* Forbid 90 or 270 degree ratation */ + transno &= ~1; + } + + coord_trans(&x, &y, 0, 0, transno); + + if (x < 0) + { + xoffset = -x - 1; + } + else + { + xoffset = 0; + } + + if (y < 0) + { + yoffset = -y - 1; + } + else + { + yoffset = 0; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, abs(y), abs(x))) return FALSE; + +#ifdef FORCE_V_IDX + v_ptr = &v_info[2]; +#endif + + msg_format_wizard(CHEAT_DUNGEON, _("特殊固定部屋(%s)を生成しました。", "Special Fix room (%s)."), v_name + v_ptr->name); + + /* Hack -- Build the vault */ + build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, + v_text + v_ptr->text, xoffset, yoffset, transno); + + return TRUE; +} + diff --git a/src/rooms-vault.h b/src/rooms-vault.h index f6deb1036..7fccebe62 100644 --- a/src/rooms-vault.h +++ b/src/rooms-vault.h @@ -1,5 +1,5 @@ -extern bool build_type7(void); -extern bool build_type8(void); -extern bool build_type10(void); -extern bool build_type17(void); - +extern bool build_type7(void); +extern bool build_type8(void); +extern bool build_type10(void); +extern bool build_type17(void); + diff --git a/src/selfinfo.c b/src/selfinfo.c index 784fe5842..72bdc2857 100644 --- a/src/selfinfo.c +++ b/src/selfinfo.c @@ -1,1808 +1,1808 @@ -/*! - * @file selfinfo.c - * @brief 自己分析処理/ Self knowledge - * @date 2018/09/07 - * @author - *
- * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
- * This software may be copied and distributed for educational, research,
- * and not for profit purposes provided that this copyright and statement
- * are included in all such copies.  Other copyrights may also apply.
- * 
- * 2018 Deskull - * @details - * spell2s.cから分離 - */ - -#include "angband.h" -#include "player-status.h" -#include "avatar.h" - -/*! - * @brief 自己分析処理(Nethackからのアイデア) / self-knowledge... idea from nethack. - * @return なし - * @details - *
- * Useful for determining powers and
- * resistences of items.  It saves the screen, clears it, then starts listing
- * attributes, a screenful at a time.  (There are a LOT of attributes to
- * list.  It will probably take 2 or 3 screens for a powerful character whose
- * using several artifacts...) -CFT
- *
- * It is now a lot more efficient. -BEN-
- *
- * See also "identify_fully()".
- *
- * Use the "show_file()" method, perhaps.
- * 
- */ -void self_knowledge(void) -{ - int i = 0, j, k; - - int v_nr = 0; - char v_string [8] [128]; - char s_string [6] [128]; - - BIT_FLAGS flgs[TR_FLAG_SIZE]; - - object_type *o_ptr; - - char Dummy[80]; - char buf[2][80]; - - concptr info[220]; - - PLAYER_LEVEL plev = p_ptr->lev; - - int percent; - - for (j = 0; j < TR_FLAG_SIZE; j++) - flgs[j] = 0L; - - p_ptr->knowledge |= (KNOW_STAT | KNOW_HPRATE); - - strcpy(Dummy, ""); - - percent = (int)(((long)p_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / - (2 * p_ptr->hitdie + - ((PY_MAX_LEVEL - 1+3) * (p_ptr->hitdie + 1)))); - - sprintf(Dummy, _("現在の体力ランク : %d/100", "Your current Life Rating is %d/100."), percent); - strcpy(buf[0], Dummy); - info[i++] = buf[0]; - info[i++] = ""; - - chg_virtue(V_KNOWLEDGE, 1); - chg_virtue(V_ENLIGHTEN, 1); - - /* Acquire item flags from equipment */ - for (k = INVEN_RARM; k < INVEN_TOTAL; k++) - { - u32b tflgs[TR_FLAG_SIZE]; - - o_ptr = &inventory[k]; - - /* Skip non-objects */ - if (!o_ptr->k_idx) continue; - object_flags(o_ptr, tflgs); - - /* Extract flags */ - for (j = 0; j < TR_FLAG_SIZE; j++) - flgs[j] |= tflgs[j]; - } - - info[i++] = _("能力の最大値", "Limits of maximum stats"); - - for (v_nr = 0; v_nr < A_MAX; v_nr++) - { - char stat_desc[80]; - - sprintf(stat_desc, "%s 18/%d", stat_names[v_nr], p_ptr->stat_max_max[v_nr]-18); - - strcpy(s_string[v_nr], stat_desc); - - info[i++] = s_string[v_nr]; - } - info[i++] = ""; - - sprintf(Dummy, _("現在の属性 : %s(%ld)", "Your alighnment : %s(%ld)"), your_alignment(), (long int)p_ptr->align); - strcpy(buf[1], Dummy); - info[i++] = buf[1]; - for (v_nr = 0; v_nr < 8; v_nr++) - { - GAME_TEXT vir_name [20]; - char vir_desc[80]; - int tester = p_ptr->virtues[v_nr]; - - strcpy(vir_name, virtue[(p_ptr->vir_types[v_nr])-1]); - - sprintf(vir_desc, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name); - if (tester < -100) - sprintf(vir_desc, _("[%s]の対極 (%d)", "You are the polar opposite of %s (%d)."), - vir_name, tester); - else if (tester < -80) - sprintf(vir_desc, _("[%s]の大敵 (%d)", "You are an arch-enemy of %s (%d)."), - vir_name, tester); - else if (tester < -60) - sprintf(vir_desc, _("[%s]の強敵 (%d)", "You are a bitter enemy of %s (%d)."), - vir_name, tester); - else if (tester < -40) - sprintf(vir_desc, _("[%s]の敵 (%d)", "You are an enemy of %s (%d)."), - vir_name, tester); - else if (tester < -20) - sprintf(vir_desc, _("[%s]の罪者 (%d)", "You have sinned against %s (%d)."), - vir_name, tester); - else if (tester < 0) - sprintf(vir_desc, _("[%s]の迷道者 (%d)", "You have strayed from the path of %s (%d)."), - vir_name, tester); - else if (tester == 0) - sprintf(vir_desc, _("[%s]の中立者 (%d)", "You are neutral to %s (%d)."), - vir_name, tester); - else if (tester < 20) - sprintf(vir_desc, _("[%s]の小徳者 (%d)", "You are somewhat virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 40) - sprintf(vir_desc, _("[%s]の中徳者 (%d)", "You are virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 60) - sprintf(vir_desc, _("[%s]の高徳者 (%d)", "You are very virtuous in %s (%d)."), - vir_name, tester); - else if (tester < 80) - sprintf(vir_desc, _("[%s]の覇者 (%d)", "You are a champion of %s (%d)."), - vir_name, tester); - else if (tester < 100) - sprintf(vir_desc, _("[%s]の偉大な覇者 (%d)", "You are a great champion of %s (%d)."), - vir_name, tester); - else - sprintf(vir_desc, _("[%s]の具現者 (%d)", "You are the living embodiment of %s (%d)."), - vir_name, tester); - - strcpy(v_string[v_nr], vir_desc); - - info[i++] = v_string[v_nr]; - } - info[i++] = ""; - - /* Racial powers... */ - if (p_ptr->mimic_form) - { - switch (p_ptr->mimic_form) - { - case MIMIC_DEMON: - case MIMIC_DEMON_LORD: - sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", - "You can nether breathe, dam. %d (cost %d)."), 3 * plev, 10+plev/3); - - info[i++] = Dummy; - break; - case MIMIC_VAMPIRE: - if (plev > 1) - { - sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", - "You can steal life from a foe, dam. %d-%d (cost %d)."), - plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); - info[i++] = Dummy; - } - break; - } - } - else - { - switch (p_ptr->prace) - { - case RACE_NIBELUNG: - case RACE_DWARF: - if (plev > 4) - info[i++] = _("あなたは罠とドアと階段を感知できる。(5 MP)", "You can find traps, doors and stairs (cost 5)."); - break; - case RACE_HOBBIT: - if (plev > 14) - { - info[i++] = _("あなたは食料を生成できる。(10 MP)", "You can produce food (cost 10)."); - } - break; - case RACE_GNOME: - if (plev > 4) - { - sprintf(Dummy, _("あなたは範囲 %d 以内にテレポートできる。(%d MP)", "You can teleport, range %d (cost %d)."), - (1 + plev), (5 + (plev / 5))); - info[i++] = Dummy; - } - break; - case RACE_HALF_ORC: - if (plev > 2) - info[i++] = _("あなたは恐怖を除去できる。(5 MP)", "You can remove fear (cost 5)."); - break; - case RACE_HALF_TROLL: - if (plev > 9) - info[i++] = _("あなたは狂暴化することができる。(12 MP) ", "You enter berserk fury (cost 12)."); - break; - case RACE_AMBERITE: - if (plev > 29) - info[i++] = _("あなたはシャドウシフトすることができる。(50 MP)", "You can Shift Shadows (cost 50)."); - - if (plev > 39) - info[i++] = _("あなたは「パターン」を心に描いて歩くことができる。(75 MP)", "You can mentally Walk the Pattern (cost 75)."); - - break; - case RACE_BARBARIAN: - if (plev > 7) - info[i++] = _("あなたは狂暴化することができる。(10 MP) ", "You can enter berserk fury (cost 10)."); - - break; - case RACE_HALF_OGRE: - if (plev > 24) - info[i++] = _("あなたは爆発のルーンを仕掛けることができる。(35 MP)", "You can set an Explosive Rune (cost 35)."); - - break; - case RACE_HALF_GIANT: - if (plev > 19) - info[i++] = _("あなたは石の壁を壊すことができる。(10 MP)", "You can break stone walls (cost 10)."); - break; - case RACE_HALF_TITAN: - if (plev > 34) - info[i++] = _("あなたはモンスターをスキャンすることができる。(20 MP)", "You can probe monsters (cost 20)."); - break; - case RACE_CYCLOPS: - if (plev > 19) - { - sprintf(Dummy, _("あなたは %d ダメージの岩石を投げることができる。(15 MP)", - "You can throw a boulder, dam. %d (cost 15)."), 3 * plev); - info[i++] = Dummy; - } - break; - case RACE_YEEK: - if (plev > 14) - info[i++] = _("あなたは恐怖を呼び起こす叫び声を発することができる。(15 MP)", "You can make a terrifying scream (cost 15)."); - break; - case RACE_KLACKON: - if (plev > 8) - { - sprintf(Dummy, _("あなたは %d ダメージの酸を吹きかけることができる。(9 MP)", "You can spit acid, dam. %d (cost 9)."), plev); - info[i++] = Dummy; - } - break; - case RACE_KOBOLD: - if (plev > 11) - { - sprintf(Dummy, - _("あなたは %d ダメージの毒矢を投げることができる。(8 MP)", "You can throw a dart of poison, dam. %d (cost 8)."), plev); - info[i++] = Dummy; - } - break; - case RACE_DARK_ELF: - if (plev > 1) - { - sprintf(Dummy, _("あなたは %d ダメージのマジック・ミサイルの呪文を使える。(2 MP)", "You can cast a Magic Missile, dam %d (cost 2)."), - (3 + ((plev-1) / 5))); - info[i++] = Dummy; - } - break; - case RACE_DRACONIAN: - sprintf(Dummy, _("あなたは %d ダメージのブレスを吐くことができる。(%d MP)", "You can breathe, dam. %d (cost %d)."), 2 * plev, plev); - info[i++] = Dummy; - break; - case RACE_MIND_FLAYER: - if (plev > 14) - sprintf(Dummy, _("あなたは %d ダメージの精神攻撃をすることができる。(12 MP)", "You can mind blast your enemies, dam %d (cost 12)."), plev); - info[i++] = Dummy; - break; - case RACE_IMP: - if (plev > 29) - { - sprintf(Dummy, _("あなたは %d ダメージのファイア・ボールの呪文を使える。(15 MP)", "You can cast a Fire Ball, dam. %d (cost 15)."), plev); - info[i++] = Dummy; - } - else if (plev > 8) - { - sprintf(Dummy, _("あなたは %d ダメージのファイア・ボルトの呪文を使える。(15 MP)", "You can cast a Fire Bolt, dam. %d (cost 15)."), plev); - info[i++] = Dummy; - } - break; - case RACE_GOLEM: - if (plev > 19) - info[i++] = _("あなたは d20+30 ターンの間肌を石に変化させられる。(15 MP)", "You can turn your skin to stone, dur d20+30 (cost 15)."); - break; - case RACE_ZOMBIE: - case RACE_SKELETON: - if (plev > 29) - info[i++] = _("あなたは失った経験値を回復することができる。(30 MP)", "You can restore lost experience (cost 30)."); - break; - case RACE_VAMPIRE: - if (plev > 1) - { - sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", "You can steal life from a foe, dam. %d-%d (cost %d)."), - plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); - info[i++] = Dummy; - } - break; - case RACE_SPECTRE: - if (plev > 3) - { - info[i++] = _("あなたは泣き叫んで敵を恐怖させることができる。(3 MP)", "You can wail to terrify your enemies (cost 3)."); - } - break; - case RACE_SPRITE: - if (plev > 11) - { - info[i++] = _("あなたは敵を眠らせる魔法の粉を投げることができる。(12 MP)", "You can throw magical dust which induces sleep (cost 12)."); - } - break; - case RACE_DEMON: - sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", - "You can breathe nether, dam. %d (cost %d)."), 3 * plev, 10+plev/3); - - info[i++] = Dummy; - break; - case RACE_KUTAR: - if (plev > 19) - info[i++] = _("あなたは d20+30 ターンの間横に伸びることができる。(15 MP)", "You can expand horizontally, dur d20+30 (cost 15)."); - break; - case RACE_ANDROID: - if (plev < 10) - sprintf(Dummy, _("あなたは %d ダメージのレイガンを撃つことができる。(7 MP)", "You can fire a ray gun with damage %d (cost 7)."), - (plev + 1) / 2); - else if (plev < 25) - sprintf(Dummy, _("あなたは %d ダメージのブラスターを撃つことができる。(13 MP)", "You can fire a blaster with damage %d (cost 13)."), plev); - else if (plev < 35) - sprintf(Dummy, _("あなたは %d ダメージのバズーカを撃つことができる。(26 MP)", "You can fire a bazooka with damage %d (cost 26)."), plev * 2); - else if (plev < 45) - sprintf(Dummy, _("あなたは %d ダメージのビームキャノンを撃つことができる。(40 MP)", - "You can fire a beam cannon with damage %d (cost 40)."), plev * 2); - else - sprintf(Dummy, _("あなたは %d ダメージのロケットを撃つことができる。(60 MP)", - "You can fire a rocket with damage %d (cost 60)."), plev * 5); - - info[i++] = Dummy; - break; - default: - break; - } - } - - switch(p_ptr->pclass) - { - case CLASS_WARRIOR: - if (plev > 39) - { - info[i++] = _("あなたはランダムな方向に対して数回攻撃することができる。(75 MP)", - "You can attack some random directions at a time (cost 75)."); - } - break; - case CLASS_HIGH_MAGE: - if (p_ptr->realm1 == REALM_HEX) break; - case CLASS_MAGE: - case CLASS_SORCERER: - if (plev > 24) - { - info[i++] = _("あなたはアイテムの魔力を吸収することができる。(1 MP)", - "You can absorb charges from an item (cost 1)."); - } - break; - case CLASS_PRIEST: - if (is_good_realm(p_ptr->realm1)) - { - if (plev > 34) - { - info[i++] = _("あなたは武器を祝福することができる。(70 MP)", "You can bless a weapon (cost 70)."); - } - } - else - { - if (plev > 41) - { - info[i++] = _("あなたは周りのすべてのモンスターを攻撃することができる。(40 MP)", "You can damages all monsters in sight (cost 40)."); - } - } - break; - case CLASS_ROGUE: - if (plev > 7) - { - info[i++] = _("あなたは攻撃して即座に逃げることができる。(12 MP)", "You can hit a monster and teleport at a time (cost 12)."); - } - break; - case CLASS_RANGER: - if (plev > 14) - { - info[i++] = _("あなたは怪物を調査することができる。(20 MP)", "You can prove monsters (cost 20)."); - } - break; - case CLASS_PALADIN: - if (is_good_realm(p_ptr->realm1)) - { - if (plev > 29) - { - info[i++] = _("あなたは聖なる槍を放つことができる。(30 MP)", "You can fires a holy spear (cost 30)."); - } - } - else - { - if (plev > 29) - { - info[i++] = _("あなたは生命力を減少させる槍を放つことができる。(30 MP)", "You can fires a spear which drains vitality (cost 30)."); - } - } - break; - case CLASS_WARRIOR_MAGE: - if (plev > 24) - { - info[i++] = _("あなたはHPをMPに変換することができる。(0 MP)", "You can convert HP to SP (cost 0)."); - info[i++] = _("あなたはMPをHPに変換することができる。(0 MP)", "You can convert SP to HP (cost 0)."); - } - break; - case CLASS_CHAOS_WARRIOR: - if (plev > 39) - { - info[i++] = _("あなたは周囲に怪物を惑わす光を発生させることができる。(50 MP)", - "You can radiate light which confuses nearby monsters (cost 50)."); - } - break; - case CLASS_MONK: - if (plev > 24) - { - info[i++] = _("あなたは構えることができる。(0 MP)", "You can assume a posture of special form (cost 0)."); - } - if (plev > 29) - { - info[i++] = _("あなたは通常の2倍の攻撃を行うことができる。(30 MP)", "You can perform double attacks in a time (cost 30)."); - } - break; - case CLASS_MINDCRAFTER: - case CLASS_FORCETRAINER: - if (plev > 14) - { - info[i++] = _("あなたは精神を集中してMPを回復させることができる。(0 MP)", "You can concentrate to regenerate your mana (cost 0)."); - } - break; - case CLASS_TOURIST: - info[i++] = _("あなたは写真を撮影することができる。(0 MP)", "You can take a photograph (cost 0)."); - if (plev > 24) - { - info[i++] = _("あなたはアイテムを完全に鑑定することができる。(20 MP)", "You can *identify* items (cost 20)."); - } - break; - case CLASS_IMITATOR: - if (plev > 29) - { - info[i++] = _("あなたは怪物の特殊攻撃をダメージ2倍でまねることができる。(100 MP)", - "You can imitate monster's special attacks with double damage (cost 100)."); - } - break; - case CLASS_BEASTMASTER: - info[i++] = _("あなたは1体の生命のあるモンスターを支配することができる。(レベル/4 MP)", "You can dominate a monster (cost level/4)."); - if (plev > 29) - { - info[i++] = _("あなたは視界内の生命のあるモンスターを支配することができる。((レベル+20)/2 MP)", - "You can dominate living monsters in sight (cost (level+20)/4)."); - } - break; - case CLASS_MAGIC_EATER: - info[i++] = _("あなたは杖/魔法棒/ロッドの魔力を自分のものにすることができる。", "You can absorb a staff, wand or rod itself."); - break; - case CLASS_RED_MAGE: - if (plev > 47) - { - info[i++] = _("あなたは1ターンに2回魔法を唱えることができる。(20 MP)", "You can cast two spells in one time (cost 20)."); - } - break; - case CLASS_SAMURAI: - { - info[i++] = _("あなたは精神を集中して気合いを溜めることができる。", "You can concentrate to regenerate your mana."); - } - if (plev > 24) - { - info[i++] = _("あなたは特殊な型で構えることができる。", "You can assume a posture of special form."); - } - break; - case CLASS_BLUE_MAGE: - info[i++] = _("あなたは相手に使われた魔法を学ぶことができる。", "You can study spells which your enemy casts on you."); - break; - case CLASS_CAVALRY: - if (plev > 9) - { - info[i++] = _("あなたはモンスターに乗って無理矢理ペットにすることができる。", "You can ride on a hostile monster forcibly to turn it into pet."); - } - break; - case CLASS_BERSERKER: - if (plev > 9) - { - info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); - } - break; - case CLASS_MIRROR_MASTER: - info[i++] = _("あなたは鏡を作り出すことができる。(2 MP)", "You can create a Mirror (cost 2)."); - info[i++] = _("あなたは鏡を割ることができる。(0 MP)", "You can break distant Mirrors (cost 0)."); - break; - case CLASS_NINJA: - if (plev > 19) - { - info[i++] = _("あなたは素早く移動することができる。", "You can walk extremery fast."); - } - break; - } - - if (p_ptr->muta1) - { - if (p_ptr->muta1 & MUT1_SPIT_ACID) - { - info[i++] = _("あなたは酸を吹きかけることができる。(ダメージ レベルX1)", "You can spit acid (dam lvl)."); - } - if (p_ptr->muta1 & MUT1_BR_FIRE) - { - info[i++] = _("あなたは炎のブレスを吐くことができる。(ダメージ レベルX2)", "You can breathe fire (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_HYPN_GAZE) - { - info[i++] = _("あなたの睨みは催眠効果をもつ。", "Your gaze is hypnotic."); - } - if (p_ptr->muta1 & MUT1_TELEKINES) - { - info[i++] = _("あなたは念動力をもっている。", "You are telekinetic."); - } - if (p_ptr->muta1 & MUT1_VTELEPORT) - { - info[i++] = _("あなたは自分の意思でテレポートできる。", "You can teleport at will."); - } - if (p_ptr->muta1 & MUT1_MIND_BLST) - { - info[i++] = _("あなたは精神攻撃を行える。(ダメージ 3~12d3)", "You can Mind Blast your enemies (3 to 12d3 dam)."); - } - if (p_ptr->muta1 & MUT1_RADIATION) - { - info[i++] = _("あなたは自分の意思で強い放射線を発生することができる。(ダメージ レベルX2)", "You can emit hard radiation at will (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_VAMPIRISM) - { - info[i++] = _("あなたは吸血鬼のように敵から生命力を吸収することができる。(ダメージ レベルX2)", - "You can drain life from a foe like a vampire (dam lvl * 2)."); - } - if (p_ptr->muta1 & MUT1_SMELL_MET) - { - info[i++] = _("あなたは近くにある貴金属をかぎ分けることができる。", "You can smell nearby precious metal."); - } - if (p_ptr->muta1 & MUT1_SMELL_MON) - { - info[i++] = _("あなたは近くのモンスターの存在をかぎ分けることができる。", "You can smell nearby monsters."); - } - if (p_ptr->muta1 & MUT1_BLINK) - { - info[i++] = _("あなたは短い距離をテレポートできる。", "You can teleport yourself short distances."); - } - if (p_ptr->muta1 & MUT1_EAT_ROCK) - { - info[i++] = _("あなたは硬い岩を食べることができる。", "You can consume solid rock."); - } - if (p_ptr->muta1 & MUT1_SWAP_POS) - { - info[i++] = _("あなたは他の者と場所を入れ替わることができる。", "You can switch locations with another being."); - } - if (p_ptr->muta1 & MUT1_SHRIEK) - { - info[i++] = _("あなたは身の毛もよだつ叫び声を発することができる。(ダメージ レベルX2)", "You can emit a horrible shriek (dam 2 * lvl)."); - } - if (p_ptr->muta1 & MUT1_ILLUMINE) - { - info[i++] = _("あなたは明るい光を放つことができる。", "You can emit bright light."); - } - if (p_ptr->muta1 & MUT1_DET_CURSE) - { - info[i++] = _("あなたは邪悪な魔法の危険を感じとることができる。", "You can feel the danger of evil magic."); - } - if (p_ptr->muta1 & MUT1_BERSERK) - { - info[i++] = _("あなたは自分の意思で狂乱戦闘状態になることができる。", "You can drive yourself into a berserk frenzy."); - } - if (p_ptr->muta1 & MUT1_POLYMORPH) - { - info[i++] = _("あなたは自分の意志で変化できる。", "You can polymorph yourself at will."); - } - if (p_ptr->muta1 & MUT1_MIDAS_TCH) - { - info[i++] = _("あなたは通常アイテムを金に変えることができる。", "You can turn ordinary items to gold."); - } - if (p_ptr->muta1 & MUT1_GROW_MOLD) - { - info[i++] = _("あなたは周囲にキノコを生やすことができる。", "You can cause mold to grow near you."); - } - if (p_ptr->muta1 & MUT1_RESIST) - { - info[i++] = _("あなたは元素の攻撃に対して身を硬くすることができる。", "You can harden yourself to the ravages of the elements."); - } - if (p_ptr->muta1 & MUT1_EARTHQUAKE) - { - info[i++] = _("あなたは周囲のダンジョンを崩壊させることができる。", "You can bring down the dungeon around your ears."); - } - if (p_ptr->muta1 & MUT1_EAT_MAGIC) - { - info[i++] = _("あなたは魔法のエネルギーを自分の物として使用できる。", "You can consume magic energy for your own use."); - } - if (p_ptr->muta1 & MUT1_WEIGH_MAG) - { - info[i++] = _("あなたは自分に影響を与える魔法の力を感じることができる。", "You can feel the strength of the magics affecting you."); - } - if (p_ptr->muta1 & MUT1_STERILITY) - { - info[i++] = _("あなたは集団的生殖不能を起こすことができる。", "You can cause mass impotence."); - } - if (p_ptr->muta1 & MUT1_PANIC_HIT) - { - info[i++] = _("あなたは攻撃した後身を守るため逃げることができる。", "You can run for your life after hitting something."); - } - if (p_ptr->muta1 & MUT1_DAZZLE) - { - info[i++] = _("あなたは混乱と盲目を引き起こす放射能を発生することができる。 ", "You can emit confusing, blinding radiation."); - } - if (p_ptr->muta1 & MUT1_LASER_EYE) - { - info[i++] = _("あなたは目からレーザー光線を発することができる。(ダメージ レベルX2)", "Your eyes can fire laser beams (dam 2 * lvl)."); - } - if (p_ptr->muta1 & MUT1_RECALL) - { - info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); - } - if (p_ptr->muta1 & MUT1_BANISH) - { - info[i++] = _("あなたは邪悪なモンスターを地獄に落とすことができる。", "You can send evil creatures directly to Hell."); - } - if (p_ptr->muta1 & MUT1_COLD_TOUCH) - { - info[i++] = _("あなたは敵を触って凍らせることができる。(ダメージ レベルX3)", "You can freeze things with a touch (dam 3 * lvl)."); - } - if (p_ptr->muta1 & MUT1_LAUNCHER) - { - info[i++] = _("あなたはアイテムを力強く投げることができる。", "You can hurl objects with great force."); - } - } - - if (p_ptr->muta2) - { - if (p_ptr->muta2 & MUT2_BERS_RAGE) - { - info[i++] = _("あなたは狂戦士化の発作を起こす。", "You are subject to berserker fits."); - } - if (p_ptr->muta2 & MUT2_COWARDICE) - { - info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); - } - if (p_ptr->muta2 & MUT2_RTELEPORT) - { - info[i++] = _("あなたはランダムにテレポートする。", "You are teleporting randomly."); - } - if (p_ptr->muta2 & MUT2_ALCOHOL) - { - info[i++] = _("あなたの体はアルコールを分泌する。", "Your body produces alcohol."); - } - if (p_ptr->muta2 & MUT2_HALLU) - { - info[i++] = _("あなたは幻覚を引き起こす精神錯乱に侵されている。", "You have a hallucinatory insanity."); - } - if (p_ptr->muta2 & MUT2_FLATULENT) - { - info[i++] = _("あなたは制御できない強烈な屁をこく。", "You are subject to uncontrollable flatulence."); - } - if (p_ptr->muta2 & MUT2_PROD_MANA) - { - info[i++] = _("あなたは制御不能な魔法のエネルギーを発している。", "You are producing magical energy uncontrollably."); - } - if (p_ptr->muta2 & MUT2_ATT_DEMON) - { - info[i++] = _("あなたはデーモンを引きつける。", "You attract demons."); - } - if (p_ptr->muta2 & MUT2_SCOR_TAIL) - { - info[i++] = _("あなたはサソリの尻尾が生えている。(毒、ダメージ 3d7)", "You have a scorpion tail (poison, 3d7)."); - } - if (p_ptr->muta2 & MUT2_HORNS) - { - info[i++] = _("あなたは角が生えている。(ダメージ 2d6)", "You have horns (dam. 2d6)."); - } - if (p_ptr->muta2 & MUT2_BEAK) - { - info[i++] = _("あなたはクチバシが生えている。(ダメージ 2d4)", "You have a beak (dam. 2d4)."); - } - if (p_ptr->muta2 & MUT2_SPEED_FLUX) - { - info[i++] = _("あなたはランダムに早く動いたり遅く動いたりする。", "You move faster or slower randomly."); - } - if (p_ptr->muta2 & MUT2_BANISH_ALL) - { - info[i++] = _("あなたは時々近くのモンスターを消滅させる。", "You sometimes cause nearby creatures to vanish."); - } - if (p_ptr->muta2 & MUT2_EAT_LIGHT) - { - info[i++] = _("あなたは時々周囲の光を吸収して栄養にする。", "You sometimes feed off of the light around you."); - } - if (p_ptr->muta2 & MUT2_TRUNK) - { - info[i++] = _("あなたは象のような鼻を持っている。(ダメージ 1d4)", "You have an elephantine trunk (dam 1d4)."); - } - if (p_ptr->muta2 & MUT2_ATT_ANIMAL) - { - info[i++] = _("あなたは動物を引きつける。", "You attract animals."); - } - if (p_ptr->muta2 & MUT2_TENTACLES) - { - info[i++] = _("あなたは邪悪な触手を持っている。(ダメージ 2d5)", "You have evil looking tentacles (dam 2d5)."); - } - if (p_ptr->muta2 & MUT2_RAW_CHAOS) - { - info[i++] = _("あなたはしばしば純カオスに包まれる。", "You occasionally are surrounded with raw chaos."); - } - if (p_ptr->muta2 & MUT2_NORMALITY) - { - info[i++] = _("あなたは変異していたが、回復してきている。", "You may be mutated, but you're recovering."); - } - if (p_ptr->muta2 & MUT2_WRAITH) - { - info[i++] = _("あなたの肉体は幽体化したり実体化したりする。", "You fade in and out of physical reality."); - } - if (p_ptr->muta2 & MUT2_POLY_WOUND) - { - info[i++] = _("あなたの健康はカオスの力に影響を受ける。", "Your health is subject to chaotic forces."); - } - if (p_ptr->muta2 & MUT2_WASTING) - { - info[i++] = _("あなたは衰弱する恐ろしい病気にかかっている。", "You have a horrible wasting disease."); - } - if (p_ptr->muta2 & MUT2_ATT_DRAGON) - { - info[i++] = _("あなたはドラゴンを引きつける。", "You attract dragons."); - } - if (p_ptr->muta2 & MUT2_WEIRD_MIND) - { - info[i++] = _("あなたの精神はランダムに拡大したり縮小したりしている。", "Your mind randomly expands and contracts."); - } - if (p_ptr->muta2 & MUT2_NAUSEA) - { - info[i++] = _("あなたの胃は非常に落ち着きがない。", "You have a seriously upset stomach."); - } - if (p_ptr->muta2 & MUT2_CHAOS_GIFT) - { - info[i++] = _("あなたはカオスの守護悪魔から褒美をうけとる。", "Chaos deities give you gifts."); - } - if (p_ptr->muta2 & MUT2_WALK_SHAD) - { - info[i++] = _("あなたはしばしば他の「影」に迷い込む。", "You occasionally stumble into other shadows."); - } - if (p_ptr->muta2 & MUT2_WARNING) - { - info[i++] = _("あなたは敵に関する警告を感じる。", "You receive warnings about your foes."); - } - if (p_ptr->muta2 & MUT2_INVULN) - { - info[i++] = _("あなたは時々負け知らずな気分になる。", "You occasionally feel invincible."); - } - if (p_ptr->muta2 & MUT2_SP_TO_HP) - { - info[i++] = _("あなたは時々血が筋肉にどっと流れる。", "Your blood sometimes rushes to your muscles."); - } - if (p_ptr->muta2 & MUT2_HP_TO_SP) - { - info[i++] = _("あなたは時々頭に血がどっと流れる。", "Your blood sometimes rushes to your head."); - } - if (p_ptr->muta2 & MUT2_DISARM) - { - info[i++] = _("あなたはよくつまづいて物を落とす。", "You occasionally stumble and drop things."); - } - } - - if (p_ptr->muta3) - { - if (p_ptr->muta3 & MUT3_HYPER_STR) - { - info[i++] = _("あなたは超人的に強い。(腕力+4)", "You are superhumanly strong (+4 STR)."); - } - if (p_ptr->muta3 & MUT3_PUNY) - { - info[i++] = _("あなたは虚弱だ。(腕力-4)", "You are puny (-4 STR)."); - } - if (p_ptr->muta3 & MUT3_HYPER_INT) - { - info[i++] = _("あなたの脳は生体コンピュータだ。(知能&賢さ+4)", "Your brain is a living computer (+4 INT/WIS)."); - } - if (p_ptr->muta3 & MUT3_MORONIC) - { - info[i++] = _("あなたは精神薄弱だ。(知能&賢さ-4)", "You are moronic (-4 INT/WIS)."); - } - if (p_ptr->muta3 & MUT3_RESILIENT) - { - info[i++] = _("あなたは非常にタフだ。(耐久+4)", "You are very resilient (+4 CON)."); - } - if (p_ptr->muta3 & MUT3_XTRA_FAT) - { - info[i++] = _("あなたは極端に太っている。(耐久+2,スピード-2)", "You are extremely fat (+2 CON, -2 speed)."); - } - if (p_ptr->muta3 & MUT3_ALBINO) - { - info[i++] = _("あなたはアルビノだ。(耐久-4)", "You are albino (-4 CON)."); - } - if (p_ptr->muta3 & MUT3_FLESH_ROT) - { - info[i++] = _("あなたの肉体は腐敗している。(耐久-2,魅力-1)", "Your flesh is rotting (-2 CON, -1 CHR)."); - } - if (p_ptr->muta3 & MUT3_SILLY_VOI) - { - info[i++] = _("あなたの声は間抜けなキーキー声だ。(魅力-4)", "Your voice is a silly squeak (-4 CHR)."); - } - if (p_ptr->muta3 & MUT3_BLANK_FAC) - { - info[i++] = _("あなたはのっぺらぼうだ。(魅力-1)", "Your face is featureless (-1 CHR)."); - } - if (p_ptr->muta3 & MUT3_ILL_NORM) - { - info[i++] = _("あなたは幻影に覆われている。", "Your appearance is masked with illusion."); - } - if (p_ptr->muta3 & MUT3_XTRA_EYES) - { - info[i++] = _("あなたは余分に二つの目を持っている。(探索+15)", "You have an extra pair of eyes (+15 search)."); - } - if (p_ptr->muta3 & MUT3_MAGIC_RES) - { - info[i++] = _("あなたは魔法への耐性をもっている。", "You are resistant to magic."); - } - if (p_ptr->muta3 & MUT3_XTRA_NOIS) - { - info[i++] = _("あなたは変な音を発している。(隠密-3)", "You make a lot of strange noise (-3 stealth)."); - } - if (p_ptr->muta3 & MUT3_INFRAVIS) - { - info[i++] = _("あなたは素晴らしい赤外線視力を持っている。(+3)", "You have remarkable infravision (+3)."); - } - if (p_ptr->muta3 & MUT3_XTRA_LEGS) - { - info[i++] = _("あなたは余分に二本の足が生えている。(加速+3)", "You have an extra pair of legs (+3 speed)."); - } - if (p_ptr->muta3 & MUT3_SHORT_LEG) - { - info[i++] = _("あなたの足は短い突起だ。(加速-3)", "Your legs are short stubs (-3 speed)."); - } - if (p_ptr->muta3 & MUT3_ELEC_TOUC) - { - info[i++] = _("あなたの血管には電流が流れている。", "Electricity is running through your veins."); - } - if (p_ptr->muta3 & MUT3_FIRE_BODY) - { - info[i++] = _("あなたの体は炎につつまれている。", "Your body is enveloped in flames."); - } - if (p_ptr->muta3 & MUT3_WART_SKIN) - { - info[i++] = _("あなたの肌はイボに被われている。(魅力-2, AC+5)", "Your skin is covered with warts (-2 CHR, +5 AC)."); - } - if (p_ptr->muta3 & MUT3_SCALES) - { - info[i++] = _("あなたの肌は鱗になっている。(魅力-1, AC+10)", "Your skin has turned into scales (-1 CHR, +10 AC)."); - } - if (p_ptr->muta3 & MUT3_IRON_SKIN) - { - info[i++] = _("あなたの肌は鉄でできている。(器用-1, AC+25)", "Your skin is made of steel (-1 DEX, +25 AC)."); - } - if (p_ptr->muta3 & MUT3_WINGS) - { - info[i++] = _("あなたは羽を持っている。", "You have wings."); - } - if (p_ptr->muta3 & MUT3_FEARLESS) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_REGEN) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_ESP) - { - /* Unnecessary */ - } - if (p_ptr->muta3 & MUT3_LIMBER) - { - info[i++] = _("あなたの体は非常にしなやかだ。(器用+3)", "Your body is very limber (+3 DEX)."); - } - if (p_ptr->muta3 & MUT3_ARTHRITIS) - { - info[i++] = _("あなたはいつも関節に痛みを感じている。(器用-3)", "Your joints ache constantly (-3 DEX)."); - } - if (p_ptr->muta3 & MUT3_VULN_ELEM) - { - info[i++] = _("あなたは元素の攻撃に弱い。", "You are susceptible to damage from the elements."); - } - if (p_ptr->muta3 & MUT3_MOTION) - { - info[i++] = _("あなたの動作は正確で力強い。(隠密+1)", "Your movements are precise and forceful (+1 STL)."); - } - if (p_ptr->muta3 & MUT3_GOOD_LUCK) - { - info[i++] = _("あなたは白いオーラにつつまれている。", "There is a white aura surrounding you."); - } - if (p_ptr->muta3 & MUT3_BAD_LUCK) - { - info[i++] = _("あなたは黒いオーラにつつまれている。", "There is a black aura surrounding you."); - } - } - - if (p_ptr->blind) - { - info[i++] = _("あなたは目が見えない。", "You cannot see."); - } - if (p_ptr->confused) - { - info[i++] = _("あなたは混乱している。", "You are confused."); - } - if (p_ptr->afraid) - { - info[i++] = _("あなたは恐怖に侵されている。", "You are terrified."); - } - if (p_ptr->cut) - { - info[i++] = _("あなたは出血している。", "You are bleeding."); - } - if (p_ptr->stun) - { - info[i++] = _("あなたはもうろうとしている。", "You are stunned."); - } - if (p_ptr->poisoned) - { - info[i++] = _("あなたは毒に侵されている。", "You are poisoned."); - } - if (p_ptr->image) - { - info[i++] = _("あなたは幻覚を見ている。", "You are hallucinating."); - } - if (p_ptr->cursed & TRC_TY_CURSE) - { - info[i++] = _("あなたは邪悪な怨念に包まれている。", "You carry an ancient foul curse."); - } - if (p_ptr->cursed & TRC_AGGRAVATE) - { - info[i++] = _("あなたはモンスターを怒らせている。", "You aggravate monsters."); - } - if (p_ptr->cursed & TRC_DRAIN_EXP) - { - info[i++] = _("あなたは経験値を吸われている。", "You are drained."); - } - if (p_ptr->cursed & TRC_SLOW_REGEN) - { - info[i++] = _("あなたの回復力は非常に遅い。", "You regenerate slowly."); - } - if (p_ptr->cursed & TRC_ADD_L_CURSE) - { - info[i++] = _("あなたの弱い呪いは増える。","Your weak curses multiply."); /* 暫定的 -- henkma */ - } - if (p_ptr->cursed & TRC_ADD_H_CURSE) - { - info[i++] = _("あなたの強い呪いは増える。","Your heavy curses multiply."); /* 暫定的 -- henkma */ - } - if (p_ptr->cursed & TRC_CALL_ANIMAL) - { - info[i++] = _("あなたは動物に狙われている。", "You attract animals."); - } - if (p_ptr->cursed & TRC_CALL_DEMON) - { - info[i++] = _("あなたは悪魔に狙われている。", "You attract demons."); - } - if (p_ptr->cursed & TRC_CALL_DRAGON) - { - info[i++] = _("あなたはドラゴンに狙われている。", "You attract dragons."); - } - if (p_ptr->cursed & TRC_COWARDICE) - { - info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); - } - if (p_ptr->cursed & TRC_TELEPORT) - { - info[i++] = _("あなたの位置はひじょうに不安定だ。", "Your position is very uncertain."); - } - if (p_ptr->cursed & TRC_LOW_MELEE) - { - info[i++] = _("あなたの武器は攻撃を外しやすい。", "Your weapon causes you to miss blows."); - } - if (p_ptr->cursed & TRC_LOW_AC) - { - info[i++] = _("あなたは攻撃を受けやすい。", "You are subject to be hit."); - } - if (p_ptr->cursed & TRC_LOW_MAGIC) - { - info[i++] = _("あなたは魔法を失敗しやすい。", "You are subject to fail spellcasting."); - } - if (p_ptr->cursed & TRC_FAST_DIGEST) - { - info[i++] = _("あなたはすぐお腹がへる。", "You have a good appetite."); - } - if (p_ptr->cursed & TRC_DRAIN_HP) - { - info[i++] = _("あなたは体力を吸われている。", "You are drained."); - } - if (p_ptr->cursed & TRC_DRAIN_MANA) - { - info[i++] = _("あなたは魔力を吸われている。", "You brain is drained."); - } - if (IS_BLESSED()) - { - info[i++] = _("あなたは高潔さを感じている。", "You feel rightous."); - } - if (IS_HERO()) - { - info[i++] = _("あなたはヒーロー気分だ。", "You feel heroic."); - } - if (p_ptr->shero) - { - info[i++] = _("あなたは戦闘狂だ。", "You are in a battle rage."); - } - if (p_ptr->protevil) - { - info[i++] = _("あなたは邪悪なる存在から守られている。", "You are protected from evil."); - } - if (p_ptr->shield) - { - info[i++] = _("あなたは神秘のシールドで守られている。", "You are protected by a mystic shield."); - } - if (IS_INVULN()) - { - info[i++] = _("あなたは現在傷つかない。", "You are temporarily invulnerable."); - } - if (p_ptr->wraith_form) - { - info[i++] = _("あなたは一時的に幽体化している。", "You are temporarily incorporeal."); - } - if (p_ptr->special_attack & ATTACK_CONFUSE) - { - info[i++] = _("あなたの手は赤く輝いている。", "Your hands are glowing dull red."); - } - if (p_ptr->special_attack & ATTACK_FIRE) - { - info[i++] = _("あなたの手は火炎に覆われている。", "You can strike the enemy with flame."); - } - if (p_ptr->special_attack & ATTACK_COLD) - { - info[i++] = _("あなたの手は冷気に覆われている。", "You can strike the enemy with cold."); - } - if (p_ptr->special_attack & ATTACK_ACID) - { - info[i++] = _("あなたの手は酸に覆われている。", "You can strike the enemy with acid."); - } - if (p_ptr->special_attack & ATTACK_ELEC) - { - info[i++] = _("あなたの手は電撃に覆われている。", "You can strike the enemy with electoric shock."); - } - if (p_ptr->special_attack & ATTACK_POIS) - { - info[i++] = _("あなたの手は毒に覆われている。", "You can strike the enemy with poison."); - } - switch (p_ptr->action) - { - case ACTION_SEARCH: - info[i++] = _("あなたはひじょうに注意深く周囲を見渡している。", "You are looking around very carefully."); - break; - } - if (p_ptr->new_spells) - { - info[i++] = _("あなたは呪文や祈りを学ぶことができる。", "You can learn some spells/prayers."); - } - if (p_ptr->word_recall) - { - info[i++] = _("あなたはすぐに帰還するだろう。", "You will soon be recalled."); - } - if (p_ptr->alter_reality) - { - info[i++] = _("あなたはすぐにこの世界を離れるだろう。", "You will soon be altered."); - } - if (p_ptr->see_infra) - { - info[i++] = _("あなたの瞳は赤外線に敏感である。", "Your eyes are sensitive to infrared light."); - } - if (p_ptr->see_inv) - { - info[i++] = _("あなたは透明なモンスターを見ることができる。", "You can see invisible creatures."); - } - if (p_ptr->levitation) - { - info[i++] = _("あなたは飛ぶことができる。", "You can fly."); - } - if (p_ptr->free_act) - { - info[i++] = _("あなたは麻痺知らずの効果を持っている。", "You have free action."); - } - if (p_ptr->regenerate) - { - info[i++] = _("あなたは素早く体力を回復する。", "You regenerate quickly."); - } - if (p_ptr->slow_digest) - { - info[i++] = _("あなたは食欲が少ない。", "Your appetite is small."); - } - if (p_ptr->telepathy) - { - info[i++] = _("あなたはテレパシー能力を持っている。", "You have ESP."); - } - if (p_ptr->esp_animal) - { - info[i++] = _("あなたは自然界の生物の存在を感じる能力を持っている。", "You sense natural creatures."); - } - if (p_ptr->esp_undead) - { - info[i++] = _("あなたはアンデッドの存在を感じる能力を持っている。", "You sense undead."); - } - if (p_ptr->esp_demon) - { - info[i++] = _("あなたは悪魔の存在を感じる能力を持っている。", "You sense demons."); - } - if (p_ptr->esp_orc) - { - info[i++] = _("あなたはオークの存在を感じる能力を持っている。", "You sense orcs."); - } - if (p_ptr->esp_troll) - { - info[i++] = _("あなたはトロルの存在を感じる能力を持っている。", "You sense trolls."); - } - if (p_ptr->esp_giant) - { - info[i++] = _("あなたは巨人の存在を感じる能力を持っている。", "You sense giants."); - } - if (p_ptr->esp_dragon) - { - info[i++] = _("あなたはドラゴンの存在を感じる能力を持っている。", "You sense dragons."); - } - if (p_ptr->esp_human) - { - info[i++] = _("あなたは人間の存在を感じる能力を持っている。", "You sense humans."); - } - if (p_ptr->esp_evil) - { - info[i++] = _("あなたは邪悪な生き物の存在を感じる能力を持っている。", "You sense evil creatures."); - } - if (p_ptr->esp_good) - { - info[i++] = _("あなたは善良な生き物の存在を感じる能力を持っている。", "You sense good creatures."); - } - if (p_ptr->esp_nonliving) - { - info[i++] = _("あなたは活動する無生物体の存在を感じる能力を持っている。", "You sense non-living creatures."); - } - if (p_ptr->esp_unique) - { - info[i++] = _("あなたは特別な強敵の存在を感じる能力を持っている。", "You sense unique monsters."); - } - if (p_ptr->hold_exp) - { - info[i++] = _("あなたは自己の経験値をしっかりと維持する。", "You have a firm hold on your experience."); - } - if (p_ptr->reflect) - { - info[i++] = _("あなたは矢の呪文を反射する。", "You reflect bolt spells."); - } - if (p_ptr->sh_fire) - { - info[i++] = _("あなたは炎のオーラに包まれている。", "You are surrounded with a fiery aura."); - } - if (p_ptr->sh_elec) - { - info[i++] = _("あなたは電気に包まれている。", "You are surrounded with electricity."); - } - if (p_ptr->sh_cold) - { - info[i++] = _("あなたは冷気のオーラに包まれている。", "You are surrounded with an aura of coldness."); - } - if (p_ptr->tim_sh_holy) - { - info[i++] = _("あなたは聖なるオーラに包まれている。", "You are surrounded with a holy aura."); - } - if (p_ptr->tim_sh_touki) - { - info[i++] = _("あなたは闘気のオーラに包まれている。", "You are surrounded with a energy aura."); - } - if (p_ptr->anti_magic) - { - info[i++] = _("あなたは反魔法シールドに包まれている。", "You are surrounded by an anti-magic shell."); - } - if (p_ptr->anti_tele) - { - info[i++] = _("あなたはテレポートできない。", "You cannot teleport."); - } - if (p_ptr->lite) - { - info[i++] = _("あなたの身体は光っている。", "You are carrying a permanent light."); - } - if (p_ptr->warning) - { - info[i++] = _("あなたは行動の前に危険を察知することができる。", "You will be warned before dangerous actions."); - } - if (p_ptr->dec_mana) - { - info[i++] = _("あなたは少ない消費魔力で魔法を唱えることができる。", "You can cast spells with fewer mana points."); - } - if (p_ptr->easy_spell) - { - info[i++] = _("あなたは低い失敗率で魔法を唱えることができる。", "Fail rate of your magic is decreased."); - } - if (p_ptr->heavy_spell) - { - info[i++] = _("あなたは高い失敗率で魔法を唱えなければいけない。", "Fail rate of your magic is increased."); - } - if (p_ptr->mighty_throw) - { - info[i++] = _("あなたは強く物を投げる。", "You can throw objects powerfully."); - } - - if (p_ptr->immune_acid) - { - info[i++] = _("あなたは酸に対する完全なる免疫を持っている。", "You are completely immune to acid."); - } - else if (p_ptr->resist_acid && IS_OPPOSE_ACID()) - { - info[i++] = _("あなたは酸への強力な耐性を持っている。", "You resist acid exceptionally well."); - } - else if (p_ptr->resist_acid || IS_OPPOSE_ACID()) - { - info[i++] = _("あなたは酸への耐性を持っている。", "You are resistant to acid."); - } - - if (p_ptr->immune_elec) - { - info[i++] = _("あなたは電撃に対する完全なる免疫を持っている。", "You are completely immune to lightning."); - } - else if (p_ptr->resist_elec && IS_OPPOSE_ELEC()) - { - info[i++] = _("あなたは電撃への強力な耐性を持っている。", "You resist lightning exceptionally well."); - } - else if (p_ptr->resist_elec || IS_OPPOSE_ELEC()) - { - info[i++] = _("あなたは電撃への耐性を持っている。", "You are resistant to lightning."); - } - - if (prace_is_(RACE_ANDROID) && !p_ptr->immune_elec) - { - info[i++] = _("あなたは電撃に弱い。", "You are susceptible to damage from lightning."); - } - - if (p_ptr->immune_fire) - { - info[i++] = _("あなたは火に対する完全なる免疫を持っている。", "You are completely immune to fire."); - } - else if (p_ptr->resist_fire && IS_OPPOSE_FIRE()) - { - info[i++] = _("あなたは火への強力な耐性を持っている。", "You resist fire exceptionally well."); - } - else if (p_ptr->resist_fire || IS_OPPOSE_FIRE()) - { - info[i++] = _("あなたは火への耐性を持っている。", "You are resistant to fire."); - } - - if (prace_is_(RACE_ENT) && !p_ptr->immune_fire) - { - info[i++] = _("あなたは火に弱い。", "You are susceptible to damage from fire."); - } - - if (p_ptr->immune_cold) - { - info[i++] = _("あなたは冷気に対する完全なる免疫を持っている。", "You are completely immune to cold."); - } - else if (p_ptr->resist_cold && IS_OPPOSE_COLD()) - { - info[i++] = _("あなたは冷気への強力な耐性を持っている。", "You resist cold exceptionally well."); - } - else if (p_ptr->resist_cold || IS_OPPOSE_COLD()) - { - info[i++] = _("あなたは冷気への耐性を持っている。", "You are resistant to cold."); - } - - if (p_ptr->resist_pois && IS_OPPOSE_POIS()) - { - info[i++] = _("あなたは毒への強力な耐性を持っている。", "You resist poison exceptionally well."); - } - else if (p_ptr->resist_pois || IS_OPPOSE_POIS()) - { - info[i++] = _("あなたは毒への耐性を持っている。", "You are resistant to poison."); - } - - if (p_ptr->resist_lite) - { - info[i++] = _("あなたは閃光への耐性を持っている。", "You are resistant to bright light."); - } - - if (prace_is_(RACE_VAMPIRE) || prace_is_(RACE_S_FAIRY) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) - { - info[i++] = _("あなたは閃光に弱い。", "You are susceptible to damage from bright light."); - } - - if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE) || p_ptr->wraith_form) - { - info[i++] = _("あなたは暗黒に対する完全なる免疫を持っている。", "You are completely immune to darkness."); - } - - else if (p_ptr->resist_dark) - { - info[i++] = _("あなたは暗黒への耐性を持っている。", "You are resistant to darkness."); - } - if (p_ptr->resist_conf) - { - info[i++] = _("あなたは混乱への耐性を持っている。", "You are resistant to confusion."); - } - if (p_ptr->resist_sound) - { - info[i++] = _("あなたは音波の衝撃への耐性を持っている。", "You are resistant to sonic attacks."); - } - if (p_ptr->resist_disen) - { - info[i++] = _("あなたは劣化への耐性を持っている。", "You are resistant to disenchantment."); - } - if (p_ptr->resist_chaos) - { - info[i++] = _("あなたはカオスの力への耐性を持っている。", "You are resistant to chaos."); - } - if (p_ptr->resist_shard) - { - info[i++] = _("あなたは破片の攻撃への耐性を持っている。", "You are resistant to blasts of shards."); - } - if (p_ptr->resist_nexus) - { - info[i++] = _("あなたは因果混乱の攻撃への耐性を持っている。", "You are resistant to nexus attacks."); - } - - if (prace_is_(RACE_SPECTRE)) - { - info[i++] = _("あなたは地獄の力を吸収できる。", "You can drain nether forces."); - } - else if (p_ptr->resist_neth) - { - info[i++] = _("あなたは地獄の力への耐性を持っている。", "You are resistant to nether forces."); - } - if (p_ptr->resist_fear) - { - info[i++] = _("あなたは全く恐怖を感じない。", "You are completely fearless."); - } - if (p_ptr->resist_blind) - { - info[i++] = _("あなたの目は盲目への耐性を持っている。", "Your eyes are resistant to blindness."); - } - if (p_ptr->resist_time) - { - info[i++] = _("あなたは時間逆転への耐性を持っている。", "You are resistant to time."); - } - - if (p_ptr->sustain_str) - { - info[i++] = _("あなたの腕力は維持されている。", "Your strength is sustained."); - } - if (p_ptr->sustain_int) - { - info[i++] = _("あなたの知能は維持されている。", "Your intelligence is sustained."); - } - if (p_ptr->sustain_wis) - { - info[i++] = _("あなたの賢さは維持されている。", "Your wisdom is sustained."); - } - if (p_ptr->sustain_con) - { - info[i++] = _("あなたの耐久力は維持されている。", "Your constitution is sustained."); - } - if (p_ptr->sustain_dex) - { - info[i++] = _("あなたの器用さは維持されている。", "Your dexterity is sustained."); - } - if (p_ptr->sustain_chr) - { - info[i++] = _("あなたの魅力は維持されている。", "Your charisma is sustained."); - } - - if (have_flag(flgs, TR_STR)) - { - info[i++] = _("あなたの腕力は装備によって影響を受けている。", "Your strength is affected by your equipment."); - } - if (have_flag(flgs, TR_INT)) - { - info[i++] = _("あなたの知能は装備によって影響を受けている。", "Your intelligence is affected by your equipment."); - } - if (have_flag(flgs, TR_WIS)) - { - info[i++] = _("あなたの賢さは装備によって影響を受けている。", "Your wisdom is affected by your equipment."); - } - if (have_flag(flgs, TR_DEX)) - { - info[i++] = _("あなたの器用さは装備によって影響を受けている。", "Your dexterity is affected by your equipment."); - } - if (have_flag(flgs, TR_CON)) - { - info[i++] = _("あなたの耐久力は装備によって影響を受けている。", "Your constitution is affected by your equipment."); - } - if (have_flag(flgs, TR_CHR)) - { - info[i++] = _("あなたの魅力は装備によって影響を受けている。", "Your charisma is affected by your equipment."); - } - - if (have_flag(flgs, TR_STEALTH)) - { - info[i++] = _("あなたの隠密行動能力は装備によって影響を受けている。", "Your stealth is affected by your equipment."); - } - if (have_flag(flgs, TR_SEARCH)) - { - info[i++] = _("あなたの探索能力は装備によって影響を受けている。", "Your searching ability is affected by your equipment."); - } - if (have_flag(flgs, TR_INFRA)) - { - info[i++] = _("あなたの赤外線視力は装備によって影響を受けている。", "Your infravision is affected by your equipment."); - } - if (have_flag(flgs, TR_TUNNEL)) - { - info[i++] = _("あなたの採掘能力は装備によって影響を受けている。", "Your digging ability is affected by your equipment."); - } - if (have_flag(flgs, TR_SPEED)) - { - info[i++] = _("あなたのスピードは装備によって影響を受けている。", "Your speed is affected by your equipment."); - } - if (have_flag(flgs, TR_BLOWS)) - { - info[i++] = _("あなたの攻撃速度は装備によって影響を受けている。", "Your attack speed is affected by your equipment."); - } - - - /* Access the current weapon */ - o_ptr = &inventory[INVEN_RARM]; - - /* Analyze the weapon */ - if (o_ptr->k_idx) - { - /* Indicate Blessing */ - if (have_flag(flgs, TR_BLESSED)) - { - info[i++] = _("あなたの武器は神の祝福を受けている。", "Your weapon has been blessed by the gods."); - } - - if (have_flag(flgs, TR_CHAOTIC)) - { - info[i++] = _("あなたの武器はログルスの徴の属性をもつ。", "Your weapon is branded with the Sign of Logrus."); - } - - if (have_flag(flgs, TR_IMPACT)) - { - info[i++] = _("あなたの武器は打撃で地震を発生することができる。", "The impact of your weapon can cause earthquakes."); - } - - if (have_flag(flgs, TR_VORPAL)) - { - info[i++] = _("あなたの武器は非常に鋭い。", "Your weapon is very sharp."); - } - - if (have_flag(flgs, TR_VAMPIRIC)) - { - info[i++] = _("あなたの武器は敵から生命力を吸収する。", "Your weapon drains life from your foes."); - } - - /* Special "Attack Bonuses" */ - if (have_flag(flgs, TR_BRAND_ACID)) - { - info[i++] = _("あなたの武器は敵を溶かす。", "Your weapon melts your foes."); - } - if (have_flag(flgs, TR_BRAND_ELEC)) - { - info[i++] = _("あなたの武器は敵を感電させる。", "Your weapon shocks your foes."); - } - if (have_flag(flgs, TR_BRAND_FIRE)) - { - info[i++] = _("あなたの武器は敵を燃やす。", "Your weapon burns your foes."); - } - if (have_flag(flgs, TR_BRAND_COLD)) - { - info[i++] = _("あなたの武器は敵を凍らせる。", "Your weapon freezes your foes."); - } - if (have_flag(flgs, TR_BRAND_POIS)) - { - info[i++] = _("あなたの武器は敵を毒で侵す。", "Your weapon poisons your foes."); - } - - /* Special "slay" flags */ - if (have_flag(flgs, TR_KILL_ANIMAL)) - { - info[i++] = _("あなたの武器は動物の天敵である。", "Your weapon is a great bane of animals."); - } - else if (have_flag(flgs, TR_SLAY_ANIMAL)) - { - info[i++] = _("あなたの武器は動物に対して強い力を発揮する。", "Your weapon strikes at animals with extra force."); - } - if (have_flag(flgs, TR_KILL_EVIL)) - { - info[i++] = _("あなたの武器は邪悪なる存在の天敵である。", "Your weapon is a great bane of evil."); - } - else if (have_flag(flgs, TR_SLAY_EVIL)) - { - info[i++] = _("あなたの武器は邪悪なる存在に対して強い力を発揮する。", "Your weapon strikes at evil with extra force."); - } - if (have_flag(flgs, TR_KILL_HUMAN)) - { - info[i++] = _("あなたの武器は人間の天敵である。", "Your weapon is a great bane of humans."); - } - else if (have_flag(flgs, TR_SLAY_HUMAN)) - { - info[i++] = _("あなたの武器は人間に対して特に強い力を発揮する。", "Your weapon is especially deadly against humans."); - } - if (have_flag(flgs, TR_KILL_UNDEAD)) - { - info[i++] = _("あなたの武器はアンデッドの天敵である。", "Your weapon is a great bane of undead."); - } - else if (have_flag(flgs, TR_SLAY_UNDEAD)) - { - info[i++] = _("あなたの武器はアンデッドに対して神聖なる力を発揮する。", "Your weapon strikes at undead with holy wrath."); - } - if (have_flag(flgs, TR_KILL_DEMON)) - { - info[i++] = _("あなたの武器はデーモンの天敵である。", "Your weapon is a great bane of demons."); - } - else if (have_flag(flgs, TR_SLAY_DEMON)) - { - info[i++] = _("あなたの武器はデーモンに対して神聖なる力を発揮する。", "Your weapon strikes at demons with holy wrath."); - } - if (have_flag(flgs, TR_KILL_ORC)) - { - info[i++] = _("あなたの武器はオークの天敵である。", "Your weapon is a great bane of orcs."); - } - else if (have_flag(flgs, TR_SLAY_ORC)) - { - info[i++] = _("あなたの武器はオークに対して特に強い力を発揮する。", "Your weapon is especially deadly against orcs."); - } - if (have_flag(flgs, TR_KILL_TROLL)) - { - info[i++] = _("あなたの武器はトロルの天敵である。", "Your weapon is a great bane of trolls."); - } - else if (have_flag(flgs, TR_SLAY_TROLL)) - { - info[i++] = _("あなたの武器はトロルに対して特に強い力を発揮する。", "Your weapon is especially deadly against trolls."); - } - if (have_flag(flgs, TR_KILL_GIANT)) - { - info[i++] = _("あなたの武器はジャイアントの天敵である。", "Your weapon is a great bane of giants."); - } - else if (have_flag(flgs, TR_SLAY_GIANT)) - { - info[i++] = _("あなたの武器はジャイアントに対して特に強い力を発揮する。", "Your weapon is especially deadly against giants."); - } - /* Special "kill" flags */ - if (have_flag(flgs, TR_KILL_DRAGON)) - { - info[i++] = _("あなたの武器はドラゴンの天敵である。", "Your weapon is a great bane of dragons."); - } - else if (have_flag(flgs, TR_SLAY_DRAGON)) - { - info[i++] = _("あなたの武器はドラゴンに対して特に強い力を発揮する。", "Your weapon is especially deadly against dragons."); - } - - if (have_flag(flgs, TR_FORCE_WEAPON)) - { - info[i++] = _("あなたの武器はMPを使って攻撃する。", "Your weapon causes greate damages using your MP."); - } - if (have_flag(flgs, TR_THROW)) - { - info[i++] = _("あなたの武器は投げやすい。", "Your weapon can be thrown well."); - } - } - - screen_save(); - - /* Erase the screen */ - for (k = 1; k < 24; k++) prt("", k, 13); - - /* Label the information */ - prt(_(" あなたの状態:", " Your Attributes:"), 1, 15); - - /* We will print on top of the map (column 13) */ - for (k = 2, j = 0; j < i; j++) - { - /* Show the info */ - prt(info[j], k++, 15); - - /* Every 20 entries (lines 2 to 21), start over */ - if ((k == 22) && (j+1 < i)) - { - prt(_("-- 続く --", "-- more --"), k, 15); - inkey(); - for (; k > 2; k--) prt("", k, 15); - } - } - - /* Pause */ - prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); - inkey(); - screen_load(); -} - -/*! - * @brief 魔法効果時間のターン数に基づいて表現IDを返す。 - * @param dur 効果ターン数 - * @return 効果時間の表現ID - */ -static int report_magics_aux(int dur) -{ - if (dur <= 5) - { - return 0; - } - else if (dur <= 10) - { - return 1; - } - else if (dur <= 20) - { - return 2; - } - else if (dur <= 50) - { - return 3; - } - else if (dur <= 100) - { - return 4; - } - else if (dur <= 200) - { - return 5; - } - else - { - return 6; - } -} - -static concptr report_magic_durations[] = -{ -#ifdef JP - "ごく短い間", - "少しの間", - "しばらくの間", - "多少長い間", - "長い間", - "非常に長い間", - "信じ難いほど長い間", - "モンスターを攻撃するまで" -#else - "for a short time", - "for a little while", - "for a while", - "for a long while", - "for a long time", - "for a very long time", - "for an incredibly long time", - "until you hit a monster" -#endif - -}; - -/*! - * @brief 現在の一時的効果一覧を返す / Report all currently active magical effects. - * @return なし - */ -void report_magics(void) -{ - int i = 0, j, k; - char Dummy[80]; - concptr info[128]; - int info2[128]; - - - if (p_ptr->blind) - { - info2[i] = report_magics_aux(p_ptr->blind); - info[i++] = _("あなたは目が見えない", "You cannot see"); - } - if (p_ptr->confused) - { - info2[i] = report_magics_aux(p_ptr->confused); - info[i++] = _("あなたは混乱している", "You are confused"); - } - if (p_ptr->afraid) - { - info2[i] = report_magics_aux(p_ptr->afraid); - info[i++] = _("あなたは恐怖に侵されている", "You are terrified"); - } - if (p_ptr->poisoned) - { - info2[i] = report_magics_aux(p_ptr->poisoned); - info[i++] = _("あなたは毒に侵されている", "You are poisoned"); - } - if (p_ptr->image) - { - info2[i] = report_magics_aux(p_ptr->image); - info[i++] = _("あなたは幻覚を見ている", "You are hallucinating"); - } - if (p_ptr->blessed) - { - info2[i] = report_magics_aux(p_ptr->blessed); - info[i++] = _("あなたは高潔さを感じている", "You feel rightous"); - } - if (p_ptr->hero) - { - info2[i] = report_magics_aux(p_ptr->hero); - info[i++] = _("あなたはヒーロー気分だ", "You feel heroic"); - } - if (p_ptr->shero) - { - info2[i] = report_magics_aux(p_ptr->shero); - info[i++] = _("あなたは戦闘狂だ", "You are in a battle rage"); - } - if (p_ptr->protevil) - { - info2[i] = report_magics_aux(p_ptr->protevil); - info[i++] = _("あなたは邪悪なる存在から守られている", "You are protected from evil"); - } - if (p_ptr->shield) - { - info2[i] = report_magics_aux(p_ptr->shield); - info[i++] = _("あなたは神秘のシールドで守られている", "You are protected by a mystic shield"); - } - if (p_ptr->invuln) - { - info2[i] = report_magics_aux(p_ptr->invuln); - info[i++] = _("あなたは無敵だ", "You are invulnerable"); - } - if (p_ptr->wraith_form) - { - info2[i] = report_magics_aux(p_ptr->wraith_form); - info[i++] = _("あなたは幽体化している", "You are incorporeal"); - } - if (p_ptr->special_attack & ATTACK_CONFUSE) - { - info2[i] = 7; - info[i++] = _("あなたの手は赤く輝いている", "Your hands are glowing dull red."); - } - if (p_ptr->word_recall) - { - info2[i] = report_magics_aux(p_ptr->word_recall); - info[i++] = _("この後帰還の詔が発動する", "You are waiting to be recalled"); - } - if (p_ptr->alter_reality) - { - info2[i] = report_magics_aux(p_ptr->alter_reality); - info[i++] = _("この後現実変容が発動する", "You waiting to be altered"); - } - if (p_ptr->oppose_acid) - { - info2[i] = report_magics_aux(p_ptr->oppose_acid); - info[i++] = _("あなたは酸への耐性を持っている", "You are resistant to acid"); - } - if (p_ptr->oppose_elec) - { - info2[i] = report_magics_aux(p_ptr->oppose_elec); - info[i++] = _("あなたは電撃への耐性を持っている", "You are resistant to lightning"); - } - if (p_ptr->oppose_fire) - { - info2[i] = report_magics_aux(p_ptr->oppose_fire); - info[i++] = _("あなたは火への耐性を持っている", "You are resistant to fire"); - } - if (p_ptr->oppose_cold) - { - info2[i] = report_magics_aux(p_ptr->oppose_cold); - info[i++] = _("あなたは冷気への耐性を持っている", "You are resistant to cold"); - } - if (p_ptr->oppose_pois) - { - info2[i] = report_magics_aux(p_ptr->oppose_pois); - info[i++] = _("あなたは毒への耐性を持っている", "You are resistant to poison"); - } - screen_save(); - - /* Erase the screen */ - for (k = 1; k < 24; k++) prt("", k, 13); - - /* Label the information */ - prt(_(" 現在かかっている魔法 :", " Your Current Magic:"), 1, 15); - - - /* We will print on top of the map (column 13) */ - for (k = 2, j = 0; j < i; j++) - { - /* Show the info */ - sprintf(Dummy, _("%-28s : 期間 - %s ", "%s %s."), info[j], - report_magic_durations[info2[j]]); - prt(Dummy, k++, 15); - - /* Every 20 entries (lines 2 to 21), start over */ - if ((k == 22) && (j + 1 < i)) - { - prt(_("-- 続く --", "-- more --"), k, 15); - inkey(); - for (; k > 2; k--) prt("", k, 15); - } - } - - /* Pause */ - prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); - inkey(); - screen_load(); -} +/*! + * @file selfinfo.c + * @brief 自己分析処理/ Self knowledge + * @date 2018/09/07 + * @author + *
+ * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies.  Other copyrights may also apply.
+ * 
+ * 2018 Deskull + * @details + * spell2s.cから分離 + */ + +#include "angband.h" +#include "player-status.h" +#include "avatar.h" + +/*! + * @brief 自己分析処理(Nethackからのアイデア) / self-knowledge... idea from nethack. + * @return なし + * @details + *
+ * Useful for determining powers and
+ * resistences of items.  It saves the screen, clears it, then starts listing
+ * attributes, a screenful at a time.  (There are a LOT of attributes to
+ * list.  It will probably take 2 or 3 screens for a powerful character whose
+ * using several artifacts...) -CFT
+ *
+ * It is now a lot more efficient. -BEN-
+ *
+ * See also "identify_fully()".
+ *
+ * Use the "show_file()" method, perhaps.
+ * 
+ */ +void self_knowledge(void) +{ + int i = 0, j, k; + + int v_nr = 0; + char v_string [8] [128]; + char s_string [6] [128]; + + BIT_FLAGS flgs[TR_FLAG_SIZE]; + + object_type *o_ptr; + + char Dummy[80]; + char buf[2][80]; + + concptr info[220]; + + PLAYER_LEVEL plev = p_ptr->lev; + + int percent; + + for (j = 0; j < TR_FLAG_SIZE; j++) + flgs[j] = 0L; + + p_ptr->knowledge |= (KNOW_STAT | KNOW_HPRATE); + + strcpy(Dummy, ""); + + percent = (int)(((long)p_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / + (2 * p_ptr->hitdie + + ((PY_MAX_LEVEL - 1+3) * (p_ptr->hitdie + 1)))); + + sprintf(Dummy, _("現在の体力ランク : %d/100", "Your current Life Rating is %d/100."), percent); + strcpy(buf[0], Dummy); + info[i++] = buf[0]; + info[i++] = ""; + + chg_virtue(V_KNOWLEDGE, 1); + chg_virtue(V_ENLIGHTEN, 1); + + /* Acquire item flags from equipment */ + for (k = INVEN_RARM; k < INVEN_TOTAL; k++) + { + u32b tflgs[TR_FLAG_SIZE]; + + o_ptr = &inventory[k]; + + /* Skip non-objects */ + if (!o_ptr->k_idx) continue; + object_flags(o_ptr, tflgs); + + /* Extract flags */ + for (j = 0; j < TR_FLAG_SIZE; j++) + flgs[j] |= tflgs[j]; + } + + info[i++] = _("能力の最大値", "Limits of maximum stats"); + + for (v_nr = 0; v_nr < A_MAX; v_nr++) + { + char stat_desc[80]; + + sprintf(stat_desc, "%s 18/%d", stat_names[v_nr], p_ptr->stat_max_max[v_nr]-18); + + strcpy(s_string[v_nr], stat_desc); + + info[i++] = s_string[v_nr]; + } + info[i++] = ""; + + sprintf(Dummy, _("現在の属性 : %s(%ld)", "Your alighnment : %s(%ld)"), your_alignment(), (long int)p_ptr->align); + strcpy(buf[1], Dummy); + info[i++] = buf[1]; + for (v_nr = 0; v_nr < 8; v_nr++) + { + GAME_TEXT vir_name [20]; + char vir_desc[80]; + int tester = p_ptr->virtues[v_nr]; + + strcpy(vir_name, virtue[(p_ptr->vir_types[v_nr])-1]); + + sprintf(vir_desc, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name); + if (tester < -100) + sprintf(vir_desc, _("[%s]の対極 (%d)", "You are the polar opposite of %s (%d)."), + vir_name, tester); + else if (tester < -80) + sprintf(vir_desc, _("[%s]の大敵 (%d)", "You are an arch-enemy of %s (%d)."), + vir_name, tester); + else if (tester < -60) + sprintf(vir_desc, _("[%s]の強敵 (%d)", "You are a bitter enemy of %s (%d)."), + vir_name, tester); + else if (tester < -40) + sprintf(vir_desc, _("[%s]の敵 (%d)", "You are an enemy of %s (%d)."), + vir_name, tester); + else if (tester < -20) + sprintf(vir_desc, _("[%s]の罪者 (%d)", "You have sinned against %s (%d)."), + vir_name, tester); + else if (tester < 0) + sprintf(vir_desc, _("[%s]の迷道者 (%d)", "You have strayed from the path of %s (%d)."), + vir_name, tester); + else if (tester == 0) + sprintf(vir_desc, _("[%s]の中立者 (%d)", "You are neutral to %s (%d)."), + vir_name, tester); + else if (tester < 20) + sprintf(vir_desc, _("[%s]の小徳者 (%d)", "You are somewhat virtuous in %s (%d)."), + vir_name, tester); + else if (tester < 40) + sprintf(vir_desc, _("[%s]の中徳者 (%d)", "You are virtuous in %s (%d)."), + vir_name, tester); + else if (tester < 60) + sprintf(vir_desc, _("[%s]の高徳者 (%d)", "You are very virtuous in %s (%d)."), + vir_name, tester); + else if (tester < 80) + sprintf(vir_desc, _("[%s]の覇者 (%d)", "You are a champion of %s (%d)."), + vir_name, tester); + else if (tester < 100) + sprintf(vir_desc, _("[%s]の偉大な覇者 (%d)", "You are a great champion of %s (%d)."), + vir_name, tester); + else + sprintf(vir_desc, _("[%s]の具現者 (%d)", "You are the living embodiment of %s (%d)."), + vir_name, tester); + + strcpy(v_string[v_nr], vir_desc); + + info[i++] = v_string[v_nr]; + } + info[i++] = ""; + + /* Racial powers... */ + if (p_ptr->mimic_form) + { + switch (p_ptr->mimic_form) + { + case MIMIC_DEMON: + case MIMIC_DEMON_LORD: + sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", + "You can nether breathe, dam. %d (cost %d)."), 3 * plev, 10+plev/3); + + info[i++] = Dummy; + break; + case MIMIC_VAMPIRE: + if (plev > 1) + { + sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", + "You can steal life from a foe, dam. %d-%d (cost %d)."), + plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); + info[i++] = Dummy; + } + break; + } + } + else + { + switch (p_ptr->prace) + { + case RACE_NIBELUNG: + case RACE_DWARF: + if (plev > 4) + info[i++] = _("あなたは罠とドアと階段を感知できる。(5 MP)", "You can find traps, doors and stairs (cost 5)."); + break; + case RACE_HOBBIT: + if (plev > 14) + { + info[i++] = _("あなたは食料を生成できる。(10 MP)", "You can produce food (cost 10)."); + } + break; + case RACE_GNOME: + if (plev > 4) + { + sprintf(Dummy, _("あなたは範囲 %d 以内にテレポートできる。(%d MP)", "You can teleport, range %d (cost %d)."), + (1 + plev), (5 + (plev / 5))); + info[i++] = Dummy; + } + break; + case RACE_HALF_ORC: + if (plev > 2) + info[i++] = _("あなたは恐怖を除去できる。(5 MP)", "You can remove fear (cost 5)."); + break; + case RACE_HALF_TROLL: + if (plev > 9) + info[i++] = _("あなたは狂暴化することができる。(12 MP) ", "You enter berserk fury (cost 12)."); + break; + case RACE_AMBERITE: + if (plev > 29) + info[i++] = _("あなたはシャドウシフトすることができる。(50 MP)", "You can Shift Shadows (cost 50)."); + + if (plev > 39) + info[i++] = _("あなたは「パターン」を心に描いて歩くことができる。(75 MP)", "You can mentally Walk the Pattern (cost 75)."); + + break; + case RACE_BARBARIAN: + if (plev > 7) + info[i++] = _("あなたは狂暴化することができる。(10 MP) ", "You can enter berserk fury (cost 10)."); + + break; + case RACE_HALF_OGRE: + if (plev > 24) + info[i++] = _("あなたは爆発のルーンを仕掛けることができる。(35 MP)", "You can set an Explosive Rune (cost 35)."); + + break; + case RACE_HALF_GIANT: + if (plev > 19) + info[i++] = _("あなたは石の壁を壊すことができる。(10 MP)", "You can break stone walls (cost 10)."); + break; + case RACE_HALF_TITAN: + if (plev > 34) + info[i++] = _("あなたはモンスターをスキャンすることができる。(20 MP)", "You can probe monsters (cost 20)."); + break; + case RACE_CYCLOPS: + if (plev > 19) + { + sprintf(Dummy, _("あなたは %d ダメージの岩石を投げることができる。(15 MP)", + "You can throw a boulder, dam. %d (cost 15)."), 3 * plev); + info[i++] = Dummy; + } + break; + case RACE_YEEK: + if (plev > 14) + info[i++] = _("あなたは恐怖を呼び起こす叫び声を発することができる。(15 MP)", "You can make a terrifying scream (cost 15)."); + break; + case RACE_KLACKON: + if (plev > 8) + { + sprintf(Dummy, _("あなたは %d ダメージの酸を吹きかけることができる。(9 MP)", "You can spit acid, dam. %d (cost 9)."), plev); + info[i++] = Dummy; + } + break; + case RACE_KOBOLD: + if (plev > 11) + { + sprintf(Dummy, + _("あなたは %d ダメージの毒矢を投げることができる。(8 MP)", "You can throw a dart of poison, dam. %d (cost 8)."), plev); + info[i++] = Dummy; + } + break; + case RACE_DARK_ELF: + if (plev > 1) + { + sprintf(Dummy, _("あなたは %d ダメージのマジック・ミサイルの呪文を使える。(2 MP)", "You can cast a Magic Missile, dam %d (cost 2)."), + (3 + ((plev-1) / 5))); + info[i++] = Dummy; + } + break; + case RACE_DRACONIAN: + sprintf(Dummy, _("あなたは %d ダメージのブレスを吐くことができる。(%d MP)", "You can breathe, dam. %d (cost %d)."), 2 * plev, plev); + info[i++] = Dummy; + break; + case RACE_MIND_FLAYER: + if (plev > 14) + sprintf(Dummy, _("あなたは %d ダメージの精神攻撃をすることができる。(12 MP)", "You can mind blast your enemies, dam %d (cost 12)."), plev); + info[i++] = Dummy; + break; + case RACE_IMP: + if (plev > 29) + { + sprintf(Dummy, _("あなたは %d ダメージのファイア・ボールの呪文を使える。(15 MP)", "You can cast a Fire Ball, dam. %d (cost 15)."), plev); + info[i++] = Dummy; + } + else if (plev > 8) + { + sprintf(Dummy, _("あなたは %d ダメージのファイア・ボルトの呪文を使える。(15 MP)", "You can cast a Fire Bolt, dam. %d (cost 15)."), plev); + info[i++] = Dummy; + } + break; + case RACE_GOLEM: + if (plev > 19) + info[i++] = _("あなたは d20+30 ターンの間肌を石に変化させられる。(15 MP)", "You can turn your skin to stone, dur d20+30 (cost 15)."); + break; + case RACE_ZOMBIE: + case RACE_SKELETON: + if (plev > 29) + info[i++] = _("あなたは失った経験値を回復することができる。(30 MP)", "You can restore lost experience (cost 30)."); + break; + case RACE_VAMPIRE: + if (plev > 1) + { + sprintf(Dummy, _("あなたは敵から %d-%d HP の生命力を吸収できる。(%d MP)", "You can steal life from a foe, dam. %d-%d (cost %d)."), + plev + MAX(1, plev / 10), plev + plev * MAX(1, plev / 10), 1 + (plev / 3)); + info[i++] = Dummy; + } + break; + case RACE_SPECTRE: + if (plev > 3) + { + info[i++] = _("あなたは泣き叫んで敵を恐怖させることができる。(3 MP)", "You can wail to terrify your enemies (cost 3)."); + } + break; + case RACE_SPRITE: + if (plev > 11) + { + info[i++] = _("あなたは敵を眠らせる魔法の粉を投げることができる。(12 MP)", "You can throw magical dust which induces sleep (cost 12)."); + } + break; + case RACE_DEMON: + sprintf(Dummy, _("あなたは %d ダメージの地獄か火炎のブレスを吐くことができる。(%d MP)", + "You can breathe nether, dam. %d (cost %d)."), 3 * plev, 10+plev/3); + + info[i++] = Dummy; + break; + case RACE_KUTAR: + if (plev > 19) + info[i++] = _("あなたは d20+30 ターンの間横に伸びることができる。(15 MP)", "You can expand horizontally, dur d20+30 (cost 15)."); + break; + case RACE_ANDROID: + if (plev < 10) + sprintf(Dummy, _("あなたは %d ダメージのレイガンを撃つことができる。(7 MP)", "You can fire a ray gun with damage %d (cost 7)."), + (plev + 1) / 2); + else if (plev < 25) + sprintf(Dummy, _("あなたは %d ダメージのブラスターを撃つことができる。(13 MP)", "You can fire a blaster with damage %d (cost 13)."), plev); + else if (plev < 35) + sprintf(Dummy, _("あなたは %d ダメージのバズーカを撃つことができる。(26 MP)", "You can fire a bazooka with damage %d (cost 26)."), plev * 2); + else if (plev < 45) + sprintf(Dummy, _("あなたは %d ダメージのビームキャノンを撃つことができる。(40 MP)", + "You can fire a beam cannon with damage %d (cost 40)."), plev * 2); + else + sprintf(Dummy, _("あなたは %d ダメージのロケットを撃つことができる。(60 MP)", + "You can fire a rocket with damage %d (cost 60)."), plev * 5); + + info[i++] = Dummy; + break; + default: + break; + } + } + + switch(p_ptr->pclass) + { + case CLASS_WARRIOR: + if (plev > 39) + { + info[i++] = _("あなたはランダムな方向に対して数回攻撃することができる。(75 MP)", + "You can attack some random directions at a time (cost 75)."); + } + break; + case CLASS_HIGH_MAGE: + if (p_ptr->realm1 == REALM_HEX) break; + case CLASS_MAGE: + case CLASS_SORCERER: + if (plev > 24) + { + info[i++] = _("あなたはアイテムの魔力を吸収することができる。(1 MP)", + "You can absorb charges from an item (cost 1)."); + } + break; + case CLASS_PRIEST: + if (is_good_realm(p_ptr->realm1)) + { + if (plev > 34) + { + info[i++] = _("あなたは武器を祝福することができる。(70 MP)", "You can bless a weapon (cost 70)."); + } + } + else + { + if (plev > 41) + { + info[i++] = _("あなたは周りのすべてのモンスターを攻撃することができる。(40 MP)", "You can damages all monsters in sight (cost 40)."); + } + } + break; + case CLASS_ROGUE: + if (plev > 7) + { + info[i++] = _("あなたは攻撃して即座に逃げることができる。(12 MP)", "You can hit a monster and teleport at a time (cost 12)."); + } + break; + case CLASS_RANGER: + if (plev > 14) + { + info[i++] = _("あなたは怪物を調査することができる。(20 MP)", "You can prove monsters (cost 20)."); + } + break; + case CLASS_PALADIN: + if (is_good_realm(p_ptr->realm1)) + { + if (plev > 29) + { + info[i++] = _("あなたは聖なる槍を放つことができる。(30 MP)", "You can fires a holy spear (cost 30)."); + } + } + else + { + if (plev > 29) + { + info[i++] = _("あなたは生命力を減少させる槍を放つことができる。(30 MP)", "You can fires a spear which drains vitality (cost 30)."); + } + } + break; + case CLASS_WARRIOR_MAGE: + if (plev > 24) + { + info[i++] = _("あなたはHPをMPに変換することができる。(0 MP)", "You can convert HP to SP (cost 0)."); + info[i++] = _("あなたはMPをHPに変換することができる。(0 MP)", "You can convert SP to HP (cost 0)."); + } + break; + case CLASS_CHAOS_WARRIOR: + if (plev > 39) + { + info[i++] = _("あなたは周囲に怪物を惑わす光を発生させることができる。(50 MP)", + "You can radiate light which confuses nearby monsters (cost 50)."); + } + break; + case CLASS_MONK: + if (plev > 24) + { + info[i++] = _("あなたは構えることができる。(0 MP)", "You can assume a posture of special form (cost 0)."); + } + if (plev > 29) + { + info[i++] = _("あなたは通常の2倍の攻撃を行うことができる。(30 MP)", "You can perform double attacks in a time (cost 30)."); + } + break; + case CLASS_MINDCRAFTER: + case CLASS_FORCETRAINER: + if (plev > 14) + { + info[i++] = _("あなたは精神を集中してMPを回復させることができる。(0 MP)", "You can concentrate to regenerate your mana (cost 0)."); + } + break; + case CLASS_TOURIST: + info[i++] = _("あなたは写真を撮影することができる。(0 MP)", "You can take a photograph (cost 0)."); + if (plev > 24) + { + info[i++] = _("あなたはアイテムを完全に鑑定することができる。(20 MP)", "You can *identify* items (cost 20)."); + } + break; + case CLASS_IMITATOR: + if (plev > 29) + { + info[i++] = _("あなたは怪物の特殊攻撃をダメージ2倍でまねることができる。(100 MP)", + "You can imitate monster's special attacks with double damage (cost 100)."); + } + break; + case CLASS_BEASTMASTER: + info[i++] = _("あなたは1体の生命のあるモンスターを支配することができる。(レベル/4 MP)", "You can dominate a monster (cost level/4)."); + if (plev > 29) + { + info[i++] = _("あなたは視界内の生命のあるモンスターを支配することができる。((レベル+20)/2 MP)", + "You can dominate living monsters in sight (cost (level+20)/4)."); + } + break; + case CLASS_MAGIC_EATER: + info[i++] = _("あなたは杖/魔法棒/ロッドの魔力を自分のものにすることができる。", "You can absorb a staff, wand or rod itself."); + break; + case CLASS_RED_MAGE: + if (plev > 47) + { + info[i++] = _("あなたは1ターンに2回魔法を唱えることができる。(20 MP)", "You can cast two spells in one time (cost 20)."); + } + break; + case CLASS_SAMURAI: + { + info[i++] = _("あなたは精神を集中して気合いを溜めることができる。", "You can concentrate to regenerate your mana."); + } + if (plev > 24) + { + info[i++] = _("あなたは特殊な型で構えることができる。", "You can assume a posture of special form."); + } + break; + case CLASS_BLUE_MAGE: + info[i++] = _("あなたは相手に使われた魔法を学ぶことができる。", "You can study spells which your enemy casts on you."); + break; + case CLASS_CAVALRY: + if (plev > 9) + { + info[i++] = _("あなたはモンスターに乗って無理矢理ペットにすることができる。", "You can ride on a hostile monster forcibly to turn it into pet."); + } + break; + case CLASS_BERSERKER: + if (plev > 9) + { + info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); + } + break; + case CLASS_MIRROR_MASTER: + info[i++] = _("あなたは鏡を作り出すことができる。(2 MP)", "You can create a Mirror (cost 2)."); + info[i++] = _("あなたは鏡を割ることができる。(0 MP)", "You can break distant Mirrors (cost 0)."); + break; + case CLASS_NINJA: + if (plev > 19) + { + info[i++] = _("あなたは素早く移動することができる。", "You can walk extremery fast."); + } + break; + } + + if (p_ptr->muta1) + { + if (p_ptr->muta1 & MUT1_SPIT_ACID) + { + info[i++] = _("あなたは酸を吹きかけることができる。(ダメージ レベルX1)", "You can spit acid (dam lvl)."); + } + if (p_ptr->muta1 & MUT1_BR_FIRE) + { + info[i++] = _("あなたは炎のブレスを吐くことができる。(ダメージ レベルX2)", "You can breathe fire (dam lvl * 2)."); + } + if (p_ptr->muta1 & MUT1_HYPN_GAZE) + { + info[i++] = _("あなたの睨みは催眠効果をもつ。", "Your gaze is hypnotic."); + } + if (p_ptr->muta1 & MUT1_TELEKINES) + { + info[i++] = _("あなたは念動力をもっている。", "You are telekinetic."); + } + if (p_ptr->muta1 & MUT1_VTELEPORT) + { + info[i++] = _("あなたは自分の意思でテレポートできる。", "You can teleport at will."); + } + if (p_ptr->muta1 & MUT1_MIND_BLST) + { + info[i++] = _("あなたは精神攻撃を行える。(ダメージ 3~12d3)", "You can Mind Blast your enemies (3 to 12d3 dam)."); + } + if (p_ptr->muta1 & MUT1_RADIATION) + { + info[i++] = _("あなたは自分の意思で強い放射線を発生することができる。(ダメージ レベルX2)", "You can emit hard radiation at will (dam lvl * 2)."); + } + if (p_ptr->muta1 & MUT1_VAMPIRISM) + { + info[i++] = _("あなたは吸血鬼のように敵から生命力を吸収することができる。(ダメージ レベルX2)", + "You can drain life from a foe like a vampire (dam lvl * 2)."); + } + if (p_ptr->muta1 & MUT1_SMELL_MET) + { + info[i++] = _("あなたは近くにある貴金属をかぎ分けることができる。", "You can smell nearby precious metal."); + } + if (p_ptr->muta1 & MUT1_SMELL_MON) + { + info[i++] = _("あなたは近くのモンスターの存在をかぎ分けることができる。", "You can smell nearby monsters."); + } + if (p_ptr->muta1 & MUT1_BLINK) + { + info[i++] = _("あなたは短い距離をテレポートできる。", "You can teleport yourself short distances."); + } + if (p_ptr->muta1 & MUT1_EAT_ROCK) + { + info[i++] = _("あなたは硬い岩を食べることができる。", "You can consume solid rock."); + } + if (p_ptr->muta1 & MUT1_SWAP_POS) + { + info[i++] = _("あなたは他の者と場所を入れ替わることができる。", "You can switch locations with another being."); + } + if (p_ptr->muta1 & MUT1_SHRIEK) + { + info[i++] = _("あなたは身の毛もよだつ叫び声を発することができる。(ダメージ レベルX2)", "You can emit a horrible shriek (dam 2 * lvl)."); + } + if (p_ptr->muta1 & MUT1_ILLUMINE) + { + info[i++] = _("あなたは明るい光を放つことができる。", "You can emit bright light."); + } + if (p_ptr->muta1 & MUT1_DET_CURSE) + { + info[i++] = _("あなたは邪悪な魔法の危険を感じとることができる。", "You can feel the danger of evil magic."); + } + if (p_ptr->muta1 & MUT1_BERSERK) + { + info[i++] = _("あなたは自分の意思で狂乱戦闘状態になることができる。", "You can drive yourself into a berserk frenzy."); + } + if (p_ptr->muta1 & MUT1_POLYMORPH) + { + info[i++] = _("あなたは自分の意志で変化できる。", "You can polymorph yourself at will."); + } + if (p_ptr->muta1 & MUT1_MIDAS_TCH) + { + info[i++] = _("あなたは通常アイテムを金に変えることができる。", "You can turn ordinary items to gold."); + } + if (p_ptr->muta1 & MUT1_GROW_MOLD) + { + info[i++] = _("あなたは周囲にキノコを生やすことができる。", "You can cause mold to grow near you."); + } + if (p_ptr->muta1 & MUT1_RESIST) + { + info[i++] = _("あなたは元素の攻撃に対して身を硬くすることができる。", "You can harden yourself to the ravages of the elements."); + } + if (p_ptr->muta1 & MUT1_EARTHQUAKE) + { + info[i++] = _("あなたは周囲のダンジョンを崩壊させることができる。", "You can bring down the dungeon around your ears."); + } + if (p_ptr->muta1 & MUT1_EAT_MAGIC) + { + info[i++] = _("あなたは魔法のエネルギーを自分の物として使用できる。", "You can consume magic energy for your own use."); + } + if (p_ptr->muta1 & MUT1_WEIGH_MAG) + { + info[i++] = _("あなたは自分に影響を与える魔法の力を感じることができる。", "You can feel the strength of the magics affecting you."); + } + if (p_ptr->muta1 & MUT1_STERILITY) + { + info[i++] = _("あなたは集団的生殖不能を起こすことができる。", "You can cause mass impotence."); + } + if (p_ptr->muta1 & MUT1_PANIC_HIT) + { + info[i++] = _("あなたは攻撃した後身を守るため逃げることができる。", "You can run for your life after hitting something."); + } + if (p_ptr->muta1 & MUT1_DAZZLE) + { + info[i++] = _("あなたは混乱と盲目を引き起こす放射能を発生することができる。 ", "You can emit confusing, blinding radiation."); + } + if (p_ptr->muta1 & MUT1_LASER_EYE) + { + info[i++] = _("あなたは目からレーザー光線を発することができる。(ダメージ レベルX2)", "Your eyes can fire laser beams (dam 2 * lvl)."); + } + if (p_ptr->muta1 & MUT1_RECALL) + { + info[i++] = _("あなたは街とダンジョンの間を行き来することができる。", "You can travel between town and the depths."); + } + if (p_ptr->muta1 & MUT1_BANISH) + { + info[i++] = _("あなたは邪悪なモンスターを地獄に落とすことができる。", "You can send evil creatures directly to Hell."); + } + if (p_ptr->muta1 & MUT1_COLD_TOUCH) + { + info[i++] = _("あなたは敵を触って凍らせることができる。(ダメージ レベルX3)", "You can freeze things with a touch (dam 3 * lvl)."); + } + if (p_ptr->muta1 & MUT1_LAUNCHER) + { + info[i++] = _("あなたはアイテムを力強く投げることができる。", "You can hurl objects with great force."); + } + } + + if (p_ptr->muta2) + { + if (p_ptr->muta2 & MUT2_BERS_RAGE) + { + info[i++] = _("あなたは狂戦士化の発作を起こす。", "You are subject to berserker fits."); + } + if (p_ptr->muta2 & MUT2_COWARDICE) + { + info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); + } + if (p_ptr->muta2 & MUT2_RTELEPORT) + { + info[i++] = _("あなたはランダムにテレポートする。", "You are teleporting randomly."); + } + if (p_ptr->muta2 & MUT2_ALCOHOL) + { + info[i++] = _("あなたの体はアルコールを分泌する。", "Your body produces alcohol."); + } + if (p_ptr->muta2 & MUT2_HALLU) + { + info[i++] = _("あなたは幻覚を引き起こす精神錯乱に侵されている。", "You have a hallucinatory insanity."); + } + if (p_ptr->muta2 & MUT2_FLATULENT) + { + info[i++] = _("あなたは制御できない強烈な屁をこく。", "You are subject to uncontrollable flatulence."); + } + if (p_ptr->muta2 & MUT2_PROD_MANA) + { + info[i++] = _("あなたは制御不能な魔法のエネルギーを発している。", "You are producing magical energy uncontrollably."); + } + if (p_ptr->muta2 & MUT2_ATT_DEMON) + { + info[i++] = _("あなたはデーモンを引きつける。", "You attract demons."); + } + if (p_ptr->muta2 & MUT2_SCOR_TAIL) + { + info[i++] = _("あなたはサソリの尻尾が生えている。(毒、ダメージ 3d7)", "You have a scorpion tail (poison, 3d7)."); + } + if (p_ptr->muta2 & MUT2_HORNS) + { + info[i++] = _("あなたは角が生えている。(ダメージ 2d6)", "You have horns (dam. 2d6)."); + } + if (p_ptr->muta2 & MUT2_BEAK) + { + info[i++] = _("あなたはクチバシが生えている。(ダメージ 2d4)", "You have a beak (dam. 2d4)."); + } + if (p_ptr->muta2 & MUT2_SPEED_FLUX) + { + info[i++] = _("あなたはランダムに早く動いたり遅く動いたりする。", "You move faster or slower randomly."); + } + if (p_ptr->muta2 & MUT2_BANISH_ALL) + { + info[i++] = _("あなたは時々近くのモンスターを消滅させる。", "You sometimes cause nearby creatures to vanish."); + } + if (p_ptr->muta2 & MUT2_EAT_LIGHT) + { + info[i++] = _("あなたは時々周囲の光を吸収して栄養にする。", "You sometimes feed off of the light around you."); + } + if (p_ptr->muta2 & MUT2_TRUNK) + { + info[i++] = _("あなたは象のような鼻を持っている。(ダメージ 1d4)", "You have an elephantine trunk (dam 1d4)."); + } + if (p_ptr->muta2 & MUT2_ATT_ANIMAL) + { + info[i++] = _("あなたは動物を引きつける。", "You attract animals."); + } + if (p_ptr->muta2 & MUT2_TENTACLES) + { + info[i++] = _("あなたは邪悪な触手を持っている。(ダメージ 2d5)", "You have evil looking tentacles (dam 2d5)."); + } + if (p_ptr->muta2 & MUT2_RAW_CHAOS) + { + info[i++] = _("あなたはしばしば純カオスに包まれる。", "You occasionally are surrounded with raw chaos."); + } + if (p_ptr->muta2 & MUT2_NORMALITY) + { + info[i++] = _("あなたは変異していたが、回復してきている。", "You may be mutated, but you're recovering."); + } + if (p_ptr->muta2 & MUT2_WRAITH) + { + info[i++] = _("あなたの肉体は幽体化したり実体化したりする。", "You fade in and out of physical reality."); + } + if (p_ptr->muta2 & MUT2_POLY_WOUND) + { + info[i++] = _("あなたの健康はカオスの力に影響を受ける。", "Your health is subject to chaotic forces."); + } + if (p_ptr->muta2 & MUT2_WASTING) + { + info[i++] = _("あなたは衰弱する恐ろしい病気にかかっている。", "You have a horrible wasting disease."); + } + if (p_ptr->muta2 & MUT2_ATT_DRAGON) + { + info[i++] = _("あなたはドラゴンを引きつける。", "You attract dragons."); + } + if (p_ptr->muta2 & MUT2_WEIRD_MIND) + { + info[i++] = _("あなたの精神はランダムに拡大したり縮小したりしている。", "Your mind randomly expands and contracts."); + } + if (p_ptr->muta2 & MUT2_NAUSEA) + { + info[i++] = _("あなたの胃は非常に落ち着きがない。", "You have a seriously upset stomach."); + } + if (p_ptr->muta2 & MUT2_CHAOS_GIFT) + { + info[i++] = _("あなたはカオスの守護悪魔から褒美をうけとる。", "Chaos deities give you gifts."); + } + if (p_ptr->muta2 & MUT2_WALK_SHAD) + { + info[i++] = _("あなたはしばしば他の「影」に迷い込む。", "You occasionally stumble into other shadows."); + } + if (p_ptr->muta2 & MUT2_WARNING) + { + info[i++] = _("あなたは敵に関する警告を感じる。", "You receive warnings about your foes."); + } + if (p_ptr->muta2 & MUT2_INVULN) + { + info[i++] = _("あなたは時々負け知らずな気分になる。", "You occasionally feel invincible."); + } + if (p_ptr->muta2 & MUT2_SP_TO_HP) + { + info[i++] = _("あなたは時々血が筋肉にどっと流れる。", "Your blood sometimes rushes to your muscles."); + } + if (p_ptr->muta2 & MUT2_HP_TO_SP) + { + info[i++] = _("あなたは時々頭に血がどっと流れる。", "Your blood sometimes rushes to your head."); + } + if (p_ptr->muta2 & MUT2_DISARM) + { + info[i++] = _("あなたはよくつまづいて物を落とす。", "You occasionally stumble and drop things."); + } + } + + if (p_ptr->muta3) + { + if (p_ptr->muta3 & MUT3_HYPER_STR) + { + info[i++] = _("あなたは超人的に強い。(腕力+4)", "You are superhumanly strong (+4 STR)."); + } + if (p_ptr->muta3 & MUT3_PUNY) + { + info[i++] = _("あなたは虚弱だ。(腕力-4)", "You are puny (-4 STR)."); + } + if (p_ptr->muta3 & MUT3_HYPER_INT) + { + info[i++] = _("あなたの脳は生体コンピュータだ。(知能&賢さ+4)", "Your brain is a living computer (+4 INT/WIS)."); + } + if (p_ptr->muta3 & MUT3_MORONIC) + { + info[i++] = _("あなたは精神薄弱だ。(知能&賢さ-4)", "You are moronic (-4 INT/WIS)."); + } + if (p_ptr->muta3 & MUT3_RESILIENT) + { + info[i++] = _("あなたは非常にタフだ。(耐久+4)", "You are very resilient (+4 CON)."); + } + if (p_ptr->muta3 & MUT3_XTRA_FAT) + { + info[i++] = _("あなたは極端に太っている。(耐久+2,スピード-2)", "You are extremely fat (+2 CON, -2 speed)."); + } + if (p_ptr->muta3 & MUT3_ALBINO) + { + info[i++] = _("あなたはアルビノだ。(耐久-4)", "You are albino (-4 CON)."); + } + if (p_ptr->muta3 & MUT3_FLESH_ROT) + { + info[i++] = _("あなたの肉体は腐敗している。(耐久-2,魅力-1)", "Your flesh is rotting (-2 CON, -1 CHR)."); + } + if (p_ptr->muta3 & MUT3_SILLY_VOI) + { + info[i++] = _("あなたの声は間抜けなキーキー声だ。(魅力-4)", "Your voice is a silly squeak (-4 CHR)."); + } + if (p_ptr->muta3 & MUT3_BLANK_FAC) + { + info[i++] = _("あなたはのっぺらぼうだ。(魅力-1)", "Your face is featureless (-1 CHR)."); + } + if (p_ptr->muta3 & MUT3_ILL_NORM) + { + info[i++] = _("あなたは幻影に覆われている。", "Your appearance is masked with illusion."); + } + if (p_ptr->muta3 & MUT3_XTRA_EYES) + { + info[i++] = _("あなたは余分に二つの目を持っている。(探索+15)", "You have an extra pair of eyes (+15 search)."); + } + if (p_ptr->muta3 & MUT3_MAGIC_RES) + { + info[i++] = _("あなたは魔法への耐性をもっている。", "You are resistant to magic."); + } + if (p_ptr->muta3 & MUT3_XTRA_NOIS) + { + info[i++] = _("あなたは変な音を発している。(隠密-3)", "You make a lot of strange noise (-3 stealth)."); + } + if (p_ptr->muta3 & MUT3_INFRAVIS) + { + info[i++] = _("あなたは素晴らしい赤外線視力を持っている。(+3)", "You have remarkable infravision (+3)."); + } + if (p_ptr->muta3 & MUT3_XTRA_LEGS) + { + info[i++] = _("あなたは余分に二本の足が生えている。(加速+3)", "You have an extra pair of legs (+3 speed)."); + } + if (p_ptr->muta3 & MUT3_SHORT_LEG) + { + info[i++] = _("あなたの足は短い突起だ。(加速-3)", "Your legs are short stubs (-3 speed)."); + } + if (p_ptr->muta3 & MUT3_ELEC_TOUC) + { + info[i++] = _("あなたの血管には電流が流れている。", "Electricity is running through your veins."); + } + if (p_ptr->muta3 & MUT3_FIRE_BODY) + { + info[i++] = _("あなたの体は炎につつまれている。", "Your body is enveloped in flames."); + } + if (p_ptr->muta3 & MUT3_WART_SKIN) + { + info[i++] = _("あなたの肌はイボに被われている。(魅力-2, AC+5)", "Your skin is covered with warts (-2 CHR, +5 AC)."); + } + if (p_ptr->muta3 & MUT3_SCALES) + { + info[i++] = _("あなたの肌は鱗になっている。(魅力-1, AC+10)", "Your skin has turned into scales (-1 CHR, +10 AC)."); + } + if (p_ptr->muta3 & MUT3_IRON_SKIN) + { + info[i++] = _("あなたの肌は鉄でできている。(器用-1, AC+25)", "Your skin is made of steel (-1 DEX, +25 AC)."); + } + if (p_ptr->muta3 & MUT3_WINGS) + { + info[i++] = _("あなたは羽を持っている。", "You have wings."); + } + if (p_ptr->muta3 & MUT3_FEARLESS) + { + /* Unnecessary */ + } + if (p_ptr->muta3 & MUT3_REGEN) + { + /* Unnecessary */ + } + if (p_ptr->muta3 & MUT3_ESP) + { + /* Unnecessary */ + } + if (p_ptr->muta3 & MUT3_LIMBER) + { + info[i++] = _("あなたの体は非常にしなやかだ。(器用+3)", "Your body is very limber (+3 DEX)."); + } + if (p_ptr->muta3 & MUT3_ARTHRITIS) + { + info[i++] = _("あなたはいつも関節に痛みを感じている。(器用-3)", "Your joints ache constantly (-3 DEX)."); + } + if (p_ptr->muta3 & MUT3_VULN_ELEM) + { + info[i++] = _("あなたは元素の攻撃に弱い。", "You are susceptible to damage from the elements."); + } + if (p_ptr->muta3 & MUT3_MOTION) + { + info[i++] = _("あなたの動作は正確で力強い。(隠密+1)", "Your movements are precise and forceful (+1 STL)."); + } + if (p_ptr->muta3 & MUT3_GOOD_LUCK) + { + info[i++] = _("あなたは白いオーラにつつまれている。", "There is a white aura surrounding you."); + } + if (p_ptr->muta3 & MUT3_BAD_LUCK) + { + info[i++] = _("あなたは黒いオーラにつつまれている。", "There is a black aura surrounding you."); + } + } + + if (p_ptr->blind) + { + info[i++] = _("あなたは目が見えない。", "You cannot see."); + } + if (p_ptr->confused) + { + info[i++] = _("あなたは混乱している。", "You are confused."); + } + if (p_ptr->afraid) + { + info[i++] = _("あなたは恐怖に侵されている。", "You are terrified."); + } + if (p_ptr->cut) + { + info[i++] = _("あなたは出血している。", "You are bleeding."); + } + if (p_ptr->stun) + { + info[i++] = _("あなたはもうろうとしている。", "You are stunned."); + } + if (p_ptr->poisoned) + { + info[i++] = _("あなたは毒に侵されている。", "You are poisoned."); + } + if (p_ptr->image) + { + info[i++] = _("あなたは幻覚を見ている。", "You are hallucinating."); + } + if (p_ptr->cursed & TRC_TY_CURSE) + { + info[i++] = _("あなたは邪悪な怨念に包まれている。", "You carry an ancient foul curse."); + } + if (p_ptr->cursed & TRC_AGGRAVATE) + { + info[i++] = _("あなたはモンスターを怒らせている。", "You aggravate monsters."); + } + if (p_ptr->cursed & TRC_DRAIN_EXP) + { + info[i++] = _("あなたは経験値を吸われている。", "You are drained."); + } + if (p_ptr->cursed & TRC_SLOW_REGEN) + { + info[i++] = _("あなたの回復力は非常に遅い。", "You regenerate slowly."); + } + if (p_ptr->cursed & TRC_ADD_L_CURSE) + { + info[i++] = _("あなたの弱い呪いは増える。","Your weak curses multiply."); /* 暫定的 -- henkma */ + } + if (p_ptr->cursed & TRC_ADD_H_CURSE) + { + info[i++] = _("あなたの強い呪いは増える。","Your heavy curses multiply."); /* 暫定的 -- henkma */ + } + if (p_ptr->cursed & TRC_CALL_ANIMAL) + { + info[i++] = _("あなたは動物に狙われている。", "You attract animals."); + } + if (p_ptr->cursed & TRC_CALL_DEMON) + { + info[i++] = _("あなたは悪魔に狙われている。", "You attract demons."); + } + if (p_ptr->cursed & TRC_CALL_DRAGON) + { + info[i++] = _("あなたはドラゴンに狙われている。", "You attract dragons."); + } + if (p_ptr->cursed & TRC_COWARDICE) + { + info[i++] = _("あなたは時々臆病になる。", "You are subject to cowardice."); + } + if (p_ptr->cursed & TRC_TELEPORT) + { + info[i++] = _("あなたの位置はひじょうに不安定だ。", "Your position is very uncertain."); + } + if (p_ptr->cursed & TRC_LOW_MELEE) + { + info[i++] = _("あなたの武器は攻撃を外しやすい。", "Your weapon causes you to miss blows."); + } + if (p_ptr->cursed & TRC_LOW_AC) + { + info[i++] = _("あなたは攻撃を受けやすい。", "You are subject to be hit."); + } + if (p_ptr->cursed & TRC_LOW_MAGIC) + { + info[i++] = _("あなたは魔法を失敗しやすい。", "You are subject to fail spellcasting."); + } + if (p_ptr->cursed & TRC_FAST_DIGEST) + { + info[i++] = _("あなたはすぐお腹がへる。", "You have a good appetite."); + } + if (p_ptr->cursed & TRC_DRAIN_HP) + { + info[i++] = _("あなたは体力を吸われている。", "You are drained."); + } + if (p_ptr->cursed & TRC_DRAIN_MANA) + { + info[i++] = _("あなたは魔力を吸われている。", "You brain is drained."); + } + if (IS_BLESSED()) + { + info[i++] = _("あなたは高潔さを感じている。", "You feel rightous."); + } + if (IS_HERO()) + { + info[i++] = _("あなたはヒーロー気分だ。", "You feel heroic."); + } + if (p_ptr->shero) + { + info[i++] = _("あなたは戦闘狂だ。", "You are in a battle rage."); + } + if (p_ptr->protevil) + { + info[i++] = _("あなたは邪悪なる存在から守られている。", "You are protected from evil."); + } + if (p_ptr->shield) + { + info[i++] = _("あなたは神秘のシールドで守られている。", "You are protected by a mystic shield."); + } + if (IS_INVULN()) + { + info[i++] = _("あなたは現在傷つかない。", "You are temporarily invulnerable."); + } + if (p_ptr->wraith_form) + { + info[i++] = _("あなたは一時的に幽体化している。", "You are temporarily incorporeal."); + } + if (p_ptr->special_attack & ATTACK_CONFUSE) + { + info[i++] = _("あなたの手は赤く輝いている。", "Your hands are glowing dull red."); + } + if (p_ptr->special_attack & ATTACK_FIRE) + { + info[i++] = _("あなたの手は火炎に覆われている。", "You can strike the enemy with flame."); + } + if (p_ptr->special_attack & ATTACK_COLD) + { + info[i++] = _("あなたの手は冷気に覆われている。", "You can strike the enemy with cold."); + } + if (p_ptr->special_attack & ATTACK_ACID) + { + info[i++] = _("あなたの手は酸に覆われている。", "You can strike the enemy with acid."); + } + if (p_ptr->special_attack & ATTACK_ELEC) + { + info[i++] = _("あなたの手は電撃に覆われている。", "You can strike the enemy with electoric shock."); + } + if (p_ptr->special_attack & ATTACK_POIS) + { + info[i++] = _("あなたの手は毒に覆われている。", "You can strike the enemy with poison."); + } + switch (p_ptr->action) + { + case ACTION_SEARCH: + info[i++] = _("あなたはひじょうに注意深く周囲を見渡している。", "You are looking around very carefully."); + break; + } + if (p_ptr->new_spells) + { + info[i++] = _("あなたは呪文や祈りを学ぶことができる。", "You can learn some spells/prayers."); + } + if (p_ptr->word_recall) + { + info[i++] = _("あなたはすぐに帰還するだろう。", "You will soon be recalled."); + } + if (p_ptr->alter_reality) + { + info[i++] = _("あなたはすぐにこの世界を離れるだろう。", "You will soon be altered."); + } + if (p_ptr->see_infra) + { + info[i++] = _("あなたの瞳は赤外線に敏感である。", "Your eyes are sensitive to infrared light."); + } + if (p_ptr->see_inv) + { + info[i++] = _("あなたは透明なモンスターを見ることができる。", "You can see invisible creatures."); + } + if (p_ptr->levitation) + { + info[i++] = _("あなたは飛ぶことができる。", "You can fly."); + } + if (p_ptr->free_act) + { + info[i++] = _("あなたは麻痺知らずの効果を持っている。", "You have free action."); + } + if (p_ptr->regenerate) + { + info[i++] = _("あなたは素早く体力を回復する。", "You regenerate quickly."); + } + if (p_ptr->slow_digest) + { + info[i++] = _("あなたは食欲が少ない。", "Your appetite is small."); + } + if (p_ptr->telepathy) + { + info[i++] = _("あなたはテレパシー能力を持っている。", "You have ESP."); + } + if (p_ptr->esp_animal) + { + info[i++] = _("あなたは自然界の生物の存在を感じる能力を持っている。", "You sense natural creatures."); + } + if (p_ptr->esp_undead) + { + info[i++] = _("あなたはアンデッドの存在を感じる能力を持っている。", "You sense undead."); + } + if (p_ptr->esp_demon) + { + info[i++] = _("あなたは悪魔の存在を感じる能力を持っている。", "You sense demons."); + } + if (p_ptr->esp_orc) + { + info[i++] = _("あなたはオークの存在を感じる能力を持っている。", "You sense orcs."); + } + if (p_ptr->esp_troll) + { + info[i++] = _("あなたはトロルの存在を感じる能力を持っている。", "You sense trolls."); + } + if (p_ptr->esp_giant) + { + info[i++] = _("あなたは巨人の存在を感じる能力を持っている。", "You sense giants."); + } + if (p_ptr->esp_dragon) + { + info[i++] = _("あなたはドラゴンの存在を感じる能力を持っている。", "You sense dragons."); + } + if (p_ptr->esp_human) + { + info[i++] = _("あなたは人間の存在を感じる能力を持っている。", "You sense humans."); + } + if (p_ptr->esp_evil) + { + info[i++] = _("あなたは邪悪な生き物の存在を感じる能力を持っている。", "You sense evil creatures."); + } + if (p_ptr->esp_good) + { + info[i++] = _("あなたは善良な生き物の存在を感じる能力を持っている。", "You sense good creatures."); + } + if (p_ptr->esp_nonliving) + { + info[i++] = _("あなたは活動する無生物体の存在を感じる能力を持っている。", "You sense non-living creatures."); + } + if (p_ptr->esp_unique) + { + info[i++] = _("あなたは特別な強敵の存在を感じる能力を持っている。", "You sense unique monsters."); + } + if (p_ptr->hold_exp) + { + info[i++] = _("あなたは自己の経験値をしっかりと維持する。", "You have a firm hold on your experience."); + } + if (p_ptr->reflect) + { + info[i++] = _("あなたは矢の呪文を反射する。", "You reflect bolt spells."); + } + if (p_ptr->sh_fire) + { + info[i++] = _("あなたは炎のオーラに包まれている。", "You are surrounded with a fiery aura."); + } + if (p_ptr->sh_elec) + { + info[i++] = _("あなたは電気に包まれている。", "You are surrounded with electricity."); + } + if (p_ptr->sh_cold) + { + info[i++] = _("あなたは冷気のオーラに包まれている。", "You are surrounded with an aura of coldness."); + } + if (p_ptr->tim_sh_holy) + { + info[i++] = _("あなたは聖なるオーラに包まれている。", "You are surrounded with a holy aura."); + } + if (p_ptr->tim_sh_touki) + { + info[i++] = _("あなたは闘気のオーラに包まれている。", "You are surrounded with a energy aura."); + } + if (p_ptr->anti_magic) + { + info[i++] = _("あなたは反魔法シールドに包まれている。", "You are surrounded by an anti-magic shell."); + } + if (p_ptr->anti_tele) + { + info[i++] = _("あなたはテレポートできない。", "You cannot teleport."); + } + if (p_ptr->lite) + { + info[i++] = _("あなたの身体は光っている。", "You are carrying a permanent light."); + } + if (p_ptr->warning) + { + info[i++] = _("あなたは行動の前に危険を察知することができる。", "You will be warned before dangerous actions."); + } + if (p_ptr->dec_mana) + { + info[i++] = _("あなたは少ない消費魔力で魔法を唱えることができる。", "You can cast spells with fewer mana points."); + } + if (p_ptr->easy_spell) + { + info[i++] = _("あなたは低い失敗率で魔法を唱えることができる。", "Fail rate of your magic is decreased."); + } + if (p_ptr->heavy_spell) + { + info[i++] = _("あなたは高い失敗率で魔法を唱えなければいけない。", "Fail rate of your magic is increased."); + } + if (p_ptr->mighty_throw) + { + info[i++] = _("あなたは強く物を投げる。", "You can throw objects powerfully."); + } + + if (p_ptr->immune_acid) + { + info[i++] = _("あなたは酸に対する完全なる免疫を持っている。", "You are completely immune to acid."); + } + else if (p_ptr->resist_acid && IS_OPPOSE_ACID()) + { + info[i++] = _("あなたは酸への強力な耐性を持っている。", "You resist acid exceptionally well."); + } + else if (p_ptr->resist_acid || IS_OPPOSE_ACID()) + { + info[i++] = _("あなたは酸への耐性を持っている。", "You are resistant to acid."); + } + + if (p_ptr->immune_elec) + { + info[i++] = _("あなたは電撃に対する完全なる免疫を持っている。", "You are completely immune to lightning."); + } + else if (p_ptr->resist_elec && IS_OPPOSE_ELEC()) + { + info[i++] = _("あなたは電撃への強力な耐性を持っている。", "You resist lightning exceptionally well."); + } + else if (p_ptr->resist_elec || IS_OPPOSE_ELEC()) + { + info[i++] = _("あなたは電撃への耐性を持っている。", "You are resistant to lightning."); + } + + if (prace_is_(RACE_ANDROID) && !p_ptr->immune_elec) + { + info[i++] = _("あなたは電撃に弱い。", "You are susceptible to damage from lightning."); + } + + if (p_ptr->immune_fire) + { + info[i++] = _("あなたは火に対する完全なる免疫を持っている。", "You are completely immune to fire."); + } + else if (p_ptr->resist_fire && IS_OPPOSE_FIRE()) + { + info[i++] = _("あなたは火への強力な耐性を持っている。", "You resist fire exceptionally well."); + } + else if (p_ptr->resist_fire || IS_OPPOSE_FIRE()) + { + info[i++] = _("あなたは火への耐性を持っている。", "You are resistant to fire."); + } + + if (prace_is_(RACE_ENT) && !p_ptr->immune_fire) + { + info[i++] = _("あなたは火に弱い。", "You are susceptible to damage from fire."); + } + + if (p_ptr->immune_cold) + { + info[i++] = _("あなたは冷気に対する完全なる免疫を持っている。", "You are completely immune to cold."); + } + else if (p_ptr->resist_cold && IS_OPPOSE_COLD()) + { + info[i++] = _("あなたは冷気への強力な耐性を持っている。", "You resist cold exceptionally well."); + } + else if (p_ptr->resist_cold || IS_OPPOSE_COLD()) + { + info[i++] = _("あなたは冷気への耐性を持っている。", "You are resistant to cold."); + } + + if (p_ptr->resist_pois && IS_OPPOSE_POIS()) + { + info[i++] = _("あなたは毒への強力な耐性を持っている。", "You resist poison exceptionally well."); + } + else if (p_ptr->resist_pois || IS_OPPOSE_POIS()) + { + info[i++] = _("あなたは毒への耐性を持っている。", "You are resistant to poison."); + } + + if (p_ptr->resist_lite) + { + info[i++] = _("あなたは閃光への耐性を持っている。", "You are resistant to bright light."); + } + + if (prace_is_(RACE_VAMPIRE) || prace_is_(RACE_S_FAIRY) || (p_ptr->mimic_form == MIMIC_VAMPIRE)) + { + info[i++] = _("あなたは閃光に弱い。", "You are susceptible to damage from bright light."); + } + + if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE) || p_ptr->wraith_form) + { + info[i++] = _("あなたは暗黒に対する完全なる免疫を持っている。", "You are completely immune to darkness."); + } + + else if (p_ptr->resist_dark) + { + info[i++] = _("あなたは暗黒への耐性を持っている。", "You are resistant to darkness."); + } + if (p_ptr->resist_conf) + { + info[i++] = _("あなたは混乱への耐性を持っている。", "You are resistant to confusion."); + } + if (p_ptr->resist_sound) + { + info[i++] = _("あなたは音波の衝撃への耐性を持っている。", "You are resistant to sonic attacks."); + } + if (p_ptr->resist_disen) + { + info[i++] = _("あなたは劣化への耐性を持っている。", "You are resistant to disenchantment."); + } + if (p_ptr->resist_chaos) + { + info[i++] = _("あなたはカオスの力への耐性を持っている。", "You are resistant to chaos."); + } + if (p_ptr->resist_shard) + { + info[i++] = _("あなたは破片の攻撃への耐性を持っている。", "You are resistant to blasts of shards."); + } + if (p_ptr->resist_nexus) + { + info[i++] = _("あなたは因果混乱の攻撃への耐性を持っている。", "You are resistant to nexus attacks."); + } + + if (prace_is_(RACE_SPECTRE)) + { + info[i++] = _("あなたは地獄の力を吸収できる。", "You can drain nether forces."); + } + else if (p_ptr->resist_neth) + { + info[i++] = _("あなたは地獄の力への耐性を持っている。", "You are resistant to nether forces."); + } + if (p_ptr->resist_fear) + { + info[i++] = _("あなたは全く恐怖を感じない。", "You are completely fearless."); + } + if (p_ptr->resist_blind) + { + info[i++] = _("あなたの目は盲目への耐性を持っている。", "Your eyes are resistant to blindness."); + } + if (p_ptr->resist_time) + { + info[i++] = _("あなたは時間逆転への耐性を持っている。", "You are resistant to time."); + } + + if (p_ptr->sustain_str) + { + info[i++] = _("あなたの腕力は維持されている。", "Your strength is sustained."); + } + if (p_ptr->sustain_int) + { + info[i++] = _("あなたの知能は維持されている。", "Your intelligence is sustained."); + } + if (p_ptr->sustain_wis) + { + info[i++] = _("あなたの賢さは維持されている。", "Your wisdom is sustained."); + } + if (p_ptr->sustain_con) + { + info[i++] = _("あなたの耐久力は維持されている。", "Your constitution is sustained."); + } + if (p_ptr->sustain_dex) + { + info[i++] = _("あなたの器用さは維持されている。", "Your dexterity is sustained."); + } + if (p_ptr->sustain_chr) + { + info[i++] = _("あなたの魅力は維持されている。", "Your charisma is sustained."); + } + + if (have_flag(flgs, TR_STR)) + { + info[i++] = _("あなたの腕力は装備によって影響を受けている。", "Your strength is affected by your equipment."); + } + if (have_flag(flgs, TR_INT)) + { + info[i++] = _("あなたの知能は装備によって影響を受けている。", "Your intelligence is affected by your equipment."); + } + if (have_flag(flgs, TR_WIS)) + { + info[i++] = _("あなたの賢さは装備によって影響を受けている。", "Your wisdom is affected by your equipment."); + } + if (have_flag(flgs, TR_DEX)) + { + info[i++] = _("あなたの器用さは装備によって影響を受けている。", "Your dexterity is affected by your equipment."); + } + if (have_flag(flgs, TR_CON)) + { + info[i++] = _("あなたの耐久力は装備によって影響を受けている。", "Your constitution is affected by your equipment."); + } + if (have_flag(flgs, TR_CHR)) + { + info[i++] = _("あなたの魅力は装備によって影響を受けている。", "Your charisma is affected by your equipment."); + } + + if (have_flag(flgs, TR_STEALTH)) + { + info[i++] = _("あなたの隠密行動能力は装備によって影響を受けている。", "Your stealth is affected by your equipment."); + } + if (have_flag(flgs, TR_SEARCH)) + { + info[i++] = _("あなたの探索能力は装備によって影響を受けている。", "Your searching ability is affected by your equipment."); + } + if (have_flag(flgs, TR_INFRA)) + { + info[i++] = _("あなたの赤外線視力は装備によって影響を受けている。", "Your infravision is affected by your equipment."); + } + if (have_flag(flgs, TR_TUNNEL)) + { + info[i++] = _("あなたの採掘能力は装備によって影響を受けている。", "Your digging ability is affected by your equipment."); + } + if (have_flag(flgs, TR_SPEED)) + { + info[i++] = _("あなたのスピードは装備によって影響を受けている。", "Your speed is affected by your equipment."); + } + if (have_flag(flgs, TR_BLOWS)) + { + info[i++] = _("あなたの攻撃速度は装備によって影響を受けている。", "Your attack speed is affected by your equipment."); + } + + + /* Access the current weapon */ + o_ptr = &inventory[INVEN_RARM]; + + /* Analyze the weapon */ + if (o_ptr->k_idx) + { + /* Indicate Blessing */ + if (have_flag(flgs, TR_BLESSED)) + { + info[i++] = _("あなたの武器は神の祝福を受けている。", "Your weapon has been blessed by the gods."); + } + + if (have_flag(flgs, TR_CHAOTIC)) + { + info[i++] = _("あなたの武器はログルスの徴の属性をもつ。", "Your weapon is branded with the Sign of Logrus."); + } + + if (have_flag(flgs, TR_IMPACT)) + { + info[i++] = _("あなたの武器は打撃で地震を発生することができる。", "The impact of your weapon can cause earthquakes."); + } + + if (have_flag(flgs, TR_VORPAL)) + { + info[i++] = _("あなたの武器は非常に鋭い。", "Your weapon is very sharp."); + } + + if (have_flag(flgs, TR_VAMPIRIC)) + { + info[i++] = _("あなたの武器は敵から生命力を吸収する。", "Your weapon drains life from your foes."); + } + + /* Special "Attack Bonuses" */ + if (have_flag(flgs, TR_BRAND_ACID)) + { + info[i++] = _("あなたの武器は敵を溶かす。", "Your weapon melts your foes."); + } + if (have_flag(flgs, TR_BRAND_ELEC)) + { + info[i++] = _("あなたの武器は敵を感電させる。", "Your weapon shocks your foes."); + } + if (have_flag(flgs, TR_BRAND_FIRE)) + { + info[i++] = _("あなたの武器は敵を燃やす。", "Your weapon burns your foes."); + } + if (have_flag(flgs, TR_BRAND_COLD)) + { + info[i++] = _("あなたの武器は敵を凍らせる。", "Your weapon freezes your foes."); + } + if (have_flag(flgs, TR_BRAND_POIS)) + { + info[i++] = _("あなたの武器は敵を毒で侵す。", "Your weapon poisons your foes."); + } + + /* Special "slay" flags */ + if (have_flag(flgs, TR_KILL_ANIMAL)) + { + info[i++] = _("あなたの武器は動物の天敵である。", "Your weapon is a great bane of animals."); + } + else if (have_flag(flgs, TR_SLAY_ANIMAL)) + { + info[i++] = _("あなたの武器は動物に対して強い力を発揮する。", "Your weapon strikes at animals with extra force."); + } + if (have_flag(flgs, TR_KILL_EVIL)) + { + info[i++] = _("あなたの武器は邪悪なる存在の天敵である。", "Your weapon is a great bane of evil."); + } + else if (have_flag(flgs, TR_SLAY_EVIL)) + { + info[i++] = _("あなたの武器は邪悪なる存在に対して強い力を発揮する。", "Your weapon strikes at evil with extra force."); + } + if (have_flag(flgs, TR_KILL_HUMAN)) + { + info[i++] = _("あなたの武器は人間の天敵である。", "Your weapon is a great bane of humans."); + } + else if (have_flag(flgs, TR_SLAY_HUMAN)) + { + info[i++] = _("あなたの武器は人間に対して特に強い力を発揮する。", "Your weapon is especially deadly against humans."); + } + if (have_flag(flgs, TR_KILL_UNDEAD)) + { + info[i++] = _("あなたの武器はアンデッドの天敵である。", "Your weapon is a great bane of undead."); + } + else if (have_flag(flgs, TR_SLAY_UNDEAD)) + { + info[i++] = _("あなたの武器はアンデッドに対して神聖なる力を発揮する。", "Your weapon strikes at undead with holy wrath."); + } + if (have_flag(flgs, TR_KILL_DEMON)) + { + info[i++] = _("あなたの武器はデーモンの天敵である。", "Your weapon is a great bane of demons."); + } + else if (have_flag(flgs, TR_SLAY_DEMON)) + { + info[i++] = _("あなたの武器はデーモンに対して神聖なる力を発揮する。", "Your weapon strikes at demons with holy wrath."); + } + if (have_flag(flgs, TR_KILL_ORC)) + { + info[i++] = _("あなたの武器はオークの天敵である。", "Your weapon is a great bane of orcs."); + } + else if (have_flag(flgs, TR_SLAY_ORC)) + { + info[i++] = _("あなたの武器はオークに対して特に強い力を発揮する。", "Your weapon is especially deadly against orcs."); + } + if (have_flag(flgs, TR_KILL_TROLL)) + { + info[i++] = _("あなたの武器はトロルの天敵である。", "Your weapon is a great bane of trolls."); + } + else if (have_flag(flgs, TR_SLAY_TROLL)) + { + info[i++] = _("あなたの武器はトロルに対して特に強い力を発揮する。", "Your weapon is especially deadly against trolls."); + } + if (have_flag(flgs, TR_KILL_GIANT)) + { + info[i++] = _("あなたの武器はジャイアントの天敵である。", "Your weapon is a great bane of giants."); + } + else if (have_flag(flgs, TR_SLAY_GIANT)) + { + info[i++] = _("あなたの武器はジャイアントに対して特に強い力を発揮する。", "Your weapon is especially deadly against giants."); + } + /* Special "kill" flags */ + if (have_flag(flgs, TR_KILL_DRAGON)) + { + info[i++] = _("あなたの武器はドラゴンの天敵である。", "Your weapon is a great bane of dragons."); + } + else if (have_flag(flgs, TR_SLAY_DRAGON)) + { + info[i++] = _("あなたの武器はドラゴンに対して特に強い力を発揮する。", "Your weapon is especially deadly against dragons."); + } + + if (have_flag(flgs, TR_FORCE_WEAPON)) + { + info[i++] = _("あなたの武器はMPを使って攻撃する。", "Your weapon causes greate damages using your MP."); + } + if (have_flag(flgs, TR_THROW)) + { + info[i++] = _("あなたの武器は投げやすい。", "Your weapon can be thrown well."); + } + } + + screen_save(); + + /* Erase the screen */ + for (k = 1; k < 24; k++) prt("", k, 13); + + /* Label the information */ + prt(_(" あなたの状態:", " Your Attributes:"), 1, 15); + + /* We will print on top of the map (column 13) */ + for (k = 2, j = 0; j < i; j++) + { + /* Show the info */ + prt(info[j], k++, 15); + + /* Every 20 entries (lines 2 to 21), start over */ + if ((k == 22) && (j+1 < i)) + { + prt(_("-- 続く --", "-- more --"), k, 15); + inkey(); + for (; k > 2; k--) prt("", k, 15); + } + } + + /* Pause */ + prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); + inkey(); + screen_load(); +} + +/*! + * @brief 魔法効果時間のターン数に基づいて表現IDを返す。 + * @param dur 効果ターン数 + * @return 効果時間の表現ID + */ +static int report_magics_aux(int dur) +{ + if (dur <= 5) + { + return 0; + } + else if (dur <= 10) + { + return 1; + } + else if (dur <= 20) + { + return 2; + } + else if (dur <= 50) + { + return 3; + } + else if (dur <= 100) + { + return 4; + } + else if (dur <= 200) + { + return 5; + } + else + { + return 6; + } +} + +static concptr report_magic_durations[] = +{ +#ifdef JP + "ごく短い間", + "少しの間", + "しばらくの間", + "多少長い間", + "長い間", + "非常に長い間", + "信じ難いほど長い間", + "モンスターを攻撃するまで" +#else + "for a short time", + "for a little while", + "for a while", + "for a long while", + "for a long time", + "for a very long time", + "for an incredibly long time", + "until you hit a monster" +#endif + +}; + +/*! + * @brief 現在の一時的効果一覧を返す / Report all currently active magical effects. + * @return なし + */ +void report_magics(void) +{ + int i = 0, j, k; + char Dummy[80]; + concptr info[128]; + int info2[128]; + + + if (p_ptr->blind) + { + info2[i] = report_magics_aux(p_ptr->blind); + info[i++] = _("あなたは目が見えない", "You cannot see"); + } + if (p_ptr->confused) + { + info2[i] = report_magics_aux(p_ptr->confused); + info[i++] = _("あなたは混乱している", "You are confused"); + } + if (p_ptr->afraid) + { + info2[i] = report_magics_aux(p_ptr->afraid); + info[i++] = _("あなたは恐怖に侵されている", "You are terrified"); + } + if (p_ptr->poisoned) + { + info2[i] = report_magics_aux(p_ptr->poisoned); + info[i++] = _("あなたは毒に侵されている", "You are poisoned"); + } + if (p_ptr->image) + { + info2[i] = report_magics_aux(p_ptr->image); + info[i++] = _("あなたは幻覚を見ている", "You are hallucinating"); + } + if (p_ptr->blessed) + { + info2[i] = report_magics_aux(p_ptr->blessed); + info[i++] = _("あなたは高潔さを感じている", "You feel rightous"); + } + if (p_ptr->hero) + { + info2[i] = report_magics_aux(p_ptr->hero); + info[i++] = _("あなたはヒーロー気分だ", "You feel heroic"); + } + if (p_ptr->shero) + { + info2[i] = report_magics_aux(p_ptr->shero); + info[i++] = _("あなたは戦闘狂だ", "You are in a battle rage"); + } + if (p_ptr->protevil) + { + info2[i] = report_magics_aux(p_ptr->protevil); + info[i++] = _("あなたは邪悪なる存在から守られている", "You are protected from evil"); + } + if (p_ptr->shield) + { + info2[i] = report_magics_aux(p_ptr->shield); + info[i++] = _("あなたは神秘のシールドで守られている", "You are protected by a mystic shield"); + } + if (p_ptr->invuln) + { + info2[i] = report_magics_aux(p_ptr->invuln); + info[i++] = _("あなたは無敵だ", "You are invulnerable"); + } + if (p_ptr->wraith_form) + { + info2[i] = report_magics_aux(p_ptr->wraith_form); + info[i++] = _("あなたは幽体化している", "You are incorporeal"); + } + if (p_ptr->special_attack & ATTACK_CONFUSE) + { + info2[i] = 7; + info[i++] = _("あなたの手は赤く輝いている", "Your hands are glowing dull red."); + } + if (p_ptr->word_recall) + { + info2[i] = report_magics_aux(p_ptr->word_recall); + info[i++] = _("この後帰還の詔が発動する", "You are waiting to be recalled"); + } + if (p_ptr->alter_reality) + { + info2[i] = report_magics_aux(p_ptr->alter_reality); + info[i++] = _("この後現実変容が発動する", "You waiting to be altered"); + } + if (p_ptr->oppose_acid) + { + info2[i] = report_magics_aux(p_ptr->oppose_acid); + info[i++] = _("あなたは酸への耐性を持っている", "You are resistant to acid"); + } + if (p_ptr->oppose_elec) + { + info2[i] = report_magics_aux(p_ptr->oppose_elec); + info[i++] = _("あなたは電撃への耐性を持っている", "You are resistant to lightning"); + } + if (p_ptr->oppose_fire) + { + info2[i] = report_magics_aux(p_ptr->oppose_fire); + info[i++] = _("あなたは火への耐性を持っている", "You are resistant to fire"); + } + if (p_ptr->oppose_cold) + { + info2[i] = report_magics_aux(p_ptr->oppose_cold); + info[i++] = _("あなたは冷気への耐性を持っている", "You are resistant to cold"); + } + if (p_ptr->oppose_pois) + { + info2[i] = report_magics_aux(p_ptr->oppose_pois); + info[i++] = _("あなたは毒への耐性を持っている", "You are resistant to poison"); + } + screen_save(); + + /* Erase the screen */ + for (k = 1; k < 24; k++) prt("", k, 13); + + /* Label the information */ + prt(_(" 現在かかっている魔法 :", " Your Current Magic:"), 1, 15); + + + /* We will print on top of the map (column 13) */ + for (k = 2, j = 0; j < i; j++) + { + /* Show the info */ + sprintf(Dummy, _("%-28s : 期間 - %s ", "%s %s."), info[j], + report_magic_durations[info2[j]]); + prt(Dummy, k++, 15); + + /* Every 20 entries (lines 2 to 21), start over */ + if ((k == 22) && (j + 1 < i)) + { + prt(_("-- 続く --", "-- more --"), k, 15); + inkey(); + for (; k > 2; k--) prt("", k, 15); + } + } + + /* Pause */ + prt(_("[何かキーを押すとゲームに戻ります]", "[Press any key to continue]"), k, 13); + inkey(); + screen_load(); +} diff --git a/src/selfinfo.h b/src/selfinfo.h index d68377c89..c4396033b 100644 --- a/src/selfinfo.h +++ b/src/selfinfo.h @@ -1,8 +1,8 @@ -/*! - * @file selfinfo.h - * @brief 自己分析機能用ヘッダファイル / - * @author 2018 Deskull - */ - -extern void self_knowledge(void); -extern void report_magics(void); +/*! + * @file selfinfo.h + * @brief 自己分析機能用ヘッダファイル / + * @author 2018 Deskull + */ + +extern void self_knowledge(void); +extern void report_magics(void); diff --git a/src/spells-status.c b/src/spells-status.c index 910540f90..8890398ce 100644 --- a/src/spells-status.c +++ b/src/spells-status.c @@ -1,14 +1,14 @@ -#include "angband.h" +#include "angband.h" #include "avatar.h" #include "spells-status.h" #include "projection.h" #include "spells.h" /*! - * @brief ƒ‚ƒ“ƒXƒ^[‰ñ•œˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param dam ˆÐ—Í - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター回復処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param dam 威力 + * @return 作用が実際にあった場合TRUEを返す */ bool heal_monster(DIRECTION dir, HIT_POINT dam) { @@ -17,10 +17,10 @@ bool heal_monster(DIRECTION dir, HIT_POINT dam) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[‰Á‘¬ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param power Œø—Í - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター加速処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ bool speed_monster(DIRECTION dir, int power) { @@ -29,10 +29,10 @@ bool speed_monster(DIRECTION dir, int power) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[Œ¸‘¬ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param power Œø—Í - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター減速処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ bool slow_monster(DIRECTION dir, int power) { @@ -41,10 +41,10 @@ bool slow_monster(DIRECTION dir, int power) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[Ã–°ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param power Œø—Í - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター催眠処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ bool sleep_monster(DIRECTION dir, int power) { @@ -53,10 +53,10 @@ bool sleep_monster(DIRECTION dir, int power) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[S‘©(STASIS)ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· - * @details ˆÐ—͂̓vƒŒƒCƒ„[ƒŒƒxƒ‹*2‚ɌŒè + * @brief モンスター拘束(STASIS)処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す + * @details 威力はプレイヤーレベル*2に固定 */ bool stasis_monster(DIRECTION dir) { @@ -64,10 +64,10 @@ bool stasis_monster(DIRECTION dir) } /*! - * @brief Ž×ˆ«‚ȃ‚ƒ“ƒXƒ^[S‘©(STASIS)ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· - * @details ˆÐ—͂̓vƒŒƒCƒ„[ƒŒƒxƒ‹*2‚ɌŒè + * @brief 邪悪なモンスター拘束(STASIS)処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す + * @details 威力はプレイヤーレベル*2に固定 */ bool stasis_evil(DIRECTION dir) { @@ -75,10 +75,10 @@ bool stasis_evil(DIRECTION dir) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[¬—ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param plev ƒvƒŒƒCƒ„[ƒŒƒxƒ‹(=Œø—Í) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター混乱処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す */ bool confuse_monster(DIRECTION dir, PLAYER_LEVEL plev) { @@ -87,10 +87,10 @@ bool confuse_monster(DIRECTION dir, PLAYER_LEVEL plev) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[žNžOˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param plev ƒvƒŒƒCƒ„[ƒŒƒxƒ‹(=Œø—Í) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター朦朧処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す */ bool stun_monster(DIRECTION dir, PLAYER_LEVEL plev) { @@ -99,10 +99,10 @@ bool stun_monster(DIRECTION dir, PLAYER_LEVEL plev) } /*! - * @brief ƒ`ƒFƒ“ƒWƒ‚ƒ“ƒXƒ^[ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param power Œø—Í - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief チェンジモンスター処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param power 効力 + * @return 作用が実際にあった場合TRUEを返す */ bool poly_monster(DIRECTION dir, int power) { @@ -114,9 +114,9 @@ bool poly_monster(DIRECTION dir, int power) } /*! - * @brief ƒNƒ[ƒ“ƒ‚ƒ“ƒXƒ^[ˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief クローンモンスター処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @return 作用が実際にあった場合TRUEを返す */ bool clone_monster(DIRECTION dir) { @@ -125,10 +125,10 @@ bool clone_monster(DIRECTION dir) } /*! - * @brief ƒ‚ƒ“ƒXƒ^[‹°Qˆ— - * @param dir •ûŒü(5‚È‚ç‚΃Oƒ[ƒoƒ‹•Ï” target_col/target_row ‚̍À•W‚ð–Ú•W‚É‚·‚é) - * @param plev ƒvƒŒƒCƒ„[ƒŒƒxƒ‹(=Œø—Í) - * @return ì—p‚ªŽÀÛ‚É‚ ‚Á‚½ê‡TRUE‚ð•Ô‚· + * @brief モンスター恐慌処理 + * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする) + * @param plev プレイヤーレベル(=効力) + * @return 作用が実際にあった場合TRUEを返す */ bool fear_monster(DIRECTION dir, PLAYER_LEVEL plev) { @@ -137,8 +137,8 @@ bool fear_monster(DIRECTION dir, PLAYER_LEVEL plev) } /*! -* @brief ‰Ì‚Ì’âŽ~‚ðˆ—‚·‚é / Stop singing if the player is a Bard -* @return ‚È‚µ +* @brief 歌の停止を処理する / Stop singing if the player is a Bard +* @return なし */ void stop_singing(void) { @@ -171,11 +171,11 @@ bool time_walk(player_type *creature_ptr) { if (creature_ptr->timewalk) { - msg_print(_("Šù‚ÉŽž‚ÍŽ~‚Ü‚Á‚Ä‚¢‚éB", "Time is already stopped.")); + msg_print(_("既に時は止まっている。", "Time is already stopped.")); return (FALSE); } creature_ptr->timewalk = TRUE; - msg_print(_("uŽž‚æIv", "You yell 'Time!'")); + msg_print(_("「時よ!」", "You yell 'Time!'")); msg_print(NULL); /* Hack */ @@ -188,9 +188,9 @@ bool time_walk(player_type *creature_ptr) } /*! - * @brief ƒvƒŒƒCƒ„[‚̃qƒbƒgƒ_ƒCƒX‚ðU‚é / Role Hitpoints - * @param options ƒXƒyƒ‹‹¤’ʃIƒvƒVƒ‡ƒ“ - * @return ‚È‚µ + * @brief プレイヤーのヒットダイスを振る / Role Hitpoints + * @param options スペル共通オプション + * @return なし */ void roll_hitdice(SPOP_FLAGS options) { @@ -240,12 +240,12 @@ void roll_hitdice(SPOP_FLAGS options) { if (options & SPOP_DEBUG) { - msg_format(_("Œ»Ý‚̗̑̓‰ƒ“ƒN‚Í %d/100 ‚Å‚·B", "Your life rate is %d/100 now."), percent); + msg_format(_("現在の体力ランクは %d/100 です。", "Your life rate is %d/100 now."), percent); p_ptr->knowledge |= KNOW_HPRATE; } else { - msg_print(_("‘̗̓‰ƒ“ƒN‚ª•Ï‚í‚Á‚½B", "Life rate is changed.")); + msg_print(_("体力ランクが変わった。", "Life rate is changed.")); p_ptr->knowledge &= ~(KNOW_HPRATE); } } @@ -260,7 +260,7 @@ bool_hack life_stream(bool_hack message, bool_hack virtue_change) } if (message) { - msg_print(_("‘Ì’†‚ɐ¶–½—Í‚ª–ž‚¿‚ ‚Ó‚ê‚Ä‚«‚½I", "You feel life flow through your body!")); + msg_print(_("体中に生命力が満ちあふれてきた!", "You feel life flow through your body!")); } restore_level(); (void)set_poisoned(0); @@ -360,7 +360,7 @@ bool_hack restore_mana(bool_hack magic_eater) p_ptr->magic_num1[i] -= ((p_ptr->magic_num2[i] < 10) ? EATER_ROD_CHARGE * 3 : p_ptr->magic_num2[i] * EATER_ROD_CHARGE / 3)*k_info[k_idx].pval; if (p_ptr->magic_num1[i] < 0) p_ptr->magic_num1[i] = 0; } - msg_print(_("“ª‚ªƒnƒbƒLƒŠ‚Æ‚µ‚½B", "You feel your head clear.")); + msg_print(_("頭がハッキリとした。", "You feel your head clear.")); p_ptr->window |= (PW_PLAYER); ident = TRUE; } @@ -368,7 +368,7 @@ bool_hack restore_mana(bool_hack magic_eater) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; - msg_print(_("“ª‚ªƒnƒbƒLƒŠ‚Æ‚µ‚½B", "You feel your head clear.")); + msg_print(_("頭がハッキリとした。", "You feel your head clear.")); p_ptr->redraw |= (PR_MANA); p_ptr->window |= (PW_PLAYER); p_ptr->window |= (PW_SPELL); diff --git a/src/spells-status.h b/src/spells-status.h index 697a0305f..451fc4f11 100644 --- a/src/spells-status.h +++ b/src/spells-status.h @@ -1,4 +1,4 @@ - + extern bool heal_monster(DIRECTION dir, HIT_POINT dam); extern bool speed_monster(DIRECTION dir, int power); extern bool slow_monster(DIRECTION dir, int power); diff --git a/src/spells-summon.c b/src/spells-summon.c index 64549e662..aa5e6d1bb 100644 --- a/src/spells-summon.c +++ b/src/spells-summon.c @@ -1,304 +1,304 @@ -#include "angband.h" -#include "spells-summon.h" - -/*! -* @brief トランプ魔法独自の召喚処理を行う / Handle summoning and failure of trump spells -* @param num summon_specific()関数を呼び出す回数 -* @param pet ペット化として召喚されるか否か -* @param y 召喚位置のy座標 -* @param x 召喚位置のx座標 -* @param lev 召喚レベル -* @param type 召喚条件ID -* @param mode モンスター生成条件フラグ -* @return モンスターが(敵対も含めて)召還されたならばTRUEを返す。 -*/ -bool trump_summoning(int num, bool pet, POSITION y, POSITION x, DEPTH lev, int type, BIT_FLAGS mode) -{ - PLAYER_LEVEL plev = p_ptr->lev; - - MONSTER_IDX who; - int i; - bool success = FALSE; - - /* Default level */ - if (!lev) lev = plev * 2 / 3 + randint1(plev / 2); - - if (pet) - { - /* Become pet */ - mode |= PM_FORCE_PET; - - /* Only sometimes allow unique monster */ - if (mode & PM_ALLOW_UNIQUE) - { - /* Forbid often */ - if (randint1(50 + plev) >= plev / 10) - mode &= ~PM_ALLOW_UNIQUE; - } - - /* Player is who summons */ - who = -1; - } - else - { - /* Prevent taming, allow unique monster */ - mode |= PM_NO_PET; - - /* Behave as if they appear by themselfs */ - who = 0; - } - - for (i = 0; i < num; i++) - { - if (summon_specific(who, y, x, lev, type, mode, '\0')) - success = TRUE; - } - - if (!success) - { - msg_print(_("誰もあなたのカードの呼び声に答えない。", "Nobody answers to your Trump call.")); - } - - return success; -} - - -bool cast_summon_demon(int power) -{ - u32b flg = 0L; - bool pet = !one_in_(3); - - if (pet) flg |= PM_FORCE_PET; - else flg |= PM_NO_PET; - if (!(pet && (p_ptr->lev < 50))) flg |= PM_ALLOW_GROUP; - - if (summon_specific((pet ? -1 : 0), p_ptr->y, p_ptr->x, power, SUMMON_DEMON, flg, '\0')) - { - msg_print(_("硫黄の悪臭が充満した。", "The area fills with a stench of sulphur and brimstone.")); - if (pet) - { - msg_print(_("「ご用でございますか、ご主人様」", "'What is thy bidding... Master?'")); - } - else - { - msg_print(_("「卑しき者よ、我は汝の下僕にあらず! お前の魂を頂くぞ!」", - "'NON SERVIAM! Wretch! I shall feast on thy mortal soul!'")); - } - } - return TRUE; -} - - -/*! -* @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer -* @param o_ptr オブジェクト構造体の参照ポインタ -* @return 生贄に使用可能な死体ならばTRUEを返す。 -*/ -bool item_tester_offer(object_type *o_ptr) -{ - /* Flasks of oil are okay */ - if (o_ptr->tval != TV_CORPSE) return (FALSE); - if (o_ptr->sval != SV_CORPSE) return (FALSE); - - if (my_strchr("pht", r_info[o_ptr->pval].d_char)) return (TRUE); - - /* Assume not okay */ - return (FALSE); -} - -/*! -* @brief 悪魔領域のグレーターデーモン召喚を処理する / Daemon spell Summon Greater Demon -* @return 処理を実行したならばTRUEを返す。 -*/ -bool cast_summon_greater_demon(void) -{ - PLAYER_LEVEL plev = p_ptr->lev; - OBJECT_IDX item; - concptr q, s; - int summon_lev; - object_type *o_ptr; - - item_tester_hook = item_tester_offer; - q = _("どの死体を捧げますか? ", "Sacrifice which corpse? "); - s = _("捧げられる死体を持っていない。", "You have nothing to scrifice."); - o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); - if (!o_ptr) return FALSE; - - summon_lev = plev * 2 / 3 + r_info[o_ptr->pval].level; - - if (summon_specific(-1, p_ptr->y, p_ptr->x, summon_lev, SUMMON_HI_DEMON, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0')) - { - msg_print(_("硫黄の悪臭が充満した。", "The area fills with a stench of sulphur and brimstone.")); - msg_print(_("「ご用でございますか、ご主人様」", "'What is thy bidding... Master?'")); - - /* Decrease the item (from the pack) */ - if (item >= 0) - { - inven_item_increase(item, -1); - inven_item_describe(item); - inven_item_optimize(item); - } - - /* Decrease the item (from the floor) */ - else - { - floor_item_increase(0 - item, -1); - floor_item_describe(0 - item); - floor_item_optimize(0 - item); - } - } - else - { - msg_print(_("悪魔は現れなかった。", "No Greater Demon arrive.")); - } - - return TRUE; -} - -/*! - * @brief 同族召喚(援軍)処理 - * @param level 召喚基準レベル - * @param y 召喚先Y座標 - * @param x 召喚先X座標 - * @param mode 召喚オプション - * @return ターンを消費した場合TRUEを返す - */ -bool summon_kin_player(DEPTH level, POSITION y, POSITION x, BIT_FLAGS mode) -{ - bool pet = (bool)(mode & PM_FORCE_PET); - SYMBOL_CODE symbol = '\0'; - if (!pet) mode |= PM_NO_PET; - - switch (p_ptr->mimic_form) - { - case MIMIC_NONE: - switch (p_ptr->prace) - { - case RACE_HUMAN: - case RACE_AMBERITE: - case RACE_BARBARIAN: - case RACE_BEASTMAN: - case RACE_DUNADAN: - symbol = 'p'; - break; - case RACE_HALF_ELF: - case RACE_ELF: - case RACE_HOBBIT: - case RACE_GNOME: - case RACE_DWARF: - case RACE_HIGH_ELF: - case RACE_NIBELUNG: - case RACE_DARK_ELF: - case RACE_MIND_FLAYER: - case RACE_KUTAR: - case RACE_S_FAIRY: - symbol = 'h'; - break; - case RACE_HALF_ORC: - symbol = 'o'; - break; - case RACE_HALF_TROLL: - symbol = 'T'; - break; - case RACE_HALF_OGRE: - symbol = 'O'; - break; - case RACE_HALF_GIANT: - case RACE_HALF_TITAN: - case RACE_CYCLOPS: - symbol = 'P'; - break; - case RACE_YEEK: - symbol = 'y'; - break; - case RACE_KLACKON: - symbol = 'K'; - break; - case RACE_KOBOLD: - symbol = 'k'; - break; - case RACE_IMP: - if (one_in_(13)) symbol = 'U'; - else symbol = 'u'; - break; - case RACE_DRACONIAN: - symbol = 'd'; - break; - case RACE_GOLEM: - case RACE_ANDROID: - symbol = 'g'; - break; - case RACE_SKELETON: - if (one_in_(13)) symbol = 'L'; - else symbol = 's'; - break; - case RACE_ZOMBIE: - symbol = 'z'; - break; - case RACE_VAMPIRE: - symbol = 'V'; - break; - case RACE_SPECTRE: - symbol = 'G'; - break; - case RACE_SPRITE: - symbol = 'I'; - break; - case RACE_ENT: - symbol = '#'; - break; - case RACE_ANGEL: - symbol = 'A'; - break; - case RACE_DEMON: - symbol = 'U'; - break; - default: - symbol = 'p'; - break; - } - break; - case MIMIC_DEMON: - if (one_in_(13)) symbol = 'U'; - else symbol = 'u'; - break; - case MIMIC_DEMON_LORD: - symbol = 'U'; - break; - case MIMIC_VAMPIRE: - symbol = 'V'; - break; - } - return summon_specific((pet ? -1 : 0), y, x, level, SUMMON_KIN, mode, symbol); -} - -/*! - * @brief サイバーデーモンの召喚 - * @param who 召喚主のモンスターID(0ならばプレイヤー) - * @param y 召喚位置Y座標 - * @param x 召喚位置X座標 - * @return 作用が実際にあった場合TRUEを返す - */ -int summon_cyber(MONSTER_IDX who, POSITION y, POSITION x) -{ - int i; - int max_cyber = (easy_band ? 1 : (dun_level / 50) + randint1(2)); - int count = 0; - BIT_FLAGS mode = PM_ALLOW_GROUP; - - /* Summoned by a monster */ - if (who > 0) - { - monster_type *m_ptr = &m_list[who]; - if (is_pet(m_ptr)) mode |= PM_FORCE_PET; - } - - if (max_cyber > 4) max_cyber = 4; - - for (i = 0; i < max_cyber; i++) - { - count += summon_specific(who, y, x, 100, SUMMON_CYBER, mode, '\0'); - } - - return count; +#include "angband.h" +#include "spells-summon.h" + +/*! +* @brief トランプ魔法独自の召喚処理を行う / Handle summoning and failure of trump spells +* @param num summon_specific()関数を呼び出す回数 +* @param pet ペット化として召喚されるか否か +* @param y 召喚位置のy座標 +* @param x 召喚位置のx座標 +* @param lev 召喚レベル +* @param type 召喚条件ID +* @param mode モンスター生成条件フラグ +* @return モンスターが(敵対も含めて)召還されたならばTRUEを返す。 +*/ +bool trump_summoning(int num, bool pet, POSITION y, POSITION x, DEPTH lev, int type, BIT_FLAGS mode) +{ + PLAYER_LEVEL plev = p_ptr->lev; + + MONSTER_IDX who; + int i; + bool success = FALSE; + + /* Default level */ + if (!lev) lev = plev * 2 / 3 + randint1(plev / 2); + + if (pet) + { + /* Become pet */ + mode |= PM_FORCE_PET; + + /* Only sometimes allow unique monster */ + if (mode & PM_ALLOW_UNIQUE) + { + /* Forbid often */ + if (randint1(50 + plev) >= plev / 10) + mode &= ~PM_ALLOW_UNIQUE; + } + + /* Player is who summons */ + who = -1; + } + else + { + /* Prevent taming, allow unique monster */ + mode |= PM_NO_PET; + + /* Behave as if they appear by themselfs */ + who = 0; + } + + for (i = 0; i < num; i++) + { + if (summon_specific(who, y, x, lev, type, mode, '\0')) + success = TRUE; + } + + if (!success) + { + msg_print(_("誰もあなたのカードの呼び声に答えない。", "Nobody answers to your Trump call.")); + } + + return success; +} + + +bool cast_summon_demon(int power) +{ + u32b flg = 0L; + bool pet = !one_in_(3); + + if (pet) flg |= PM_FORCE_PET; + else flg |= PM_NO_PET; + if (!(pet && (p_ptr->lev < 50))) flg |= PM_ALLOW_GROUP; + + if (summon_specific((pet ? -1 : 0), p_ptr->y, p_ptr->x, power, SUMMON_DEMON, flg, '\0')) + { + msg_print(_("硫黄の悪臭が充満した。", "The area fills with a stench of sulphur and brimstone.")); + if (pet) + { + msg_print(_("「ご用でございますか、ご主人様」", "'What is thy bidding... Master?'")); + } + else + { + msg_print(_("「卑しき者よ、我は汝の下僕にあらず! お前の魂を頂くぞ!」", + "'NON SERVIAM! Wretch! I shall feast on thy mortal soul!'")); + } + } + return TRUE; +} + + +/*! +* @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer +* @param o_ptr オブジェクト構造体の参照ポインタ +* @return 生贄に使用可能な死体ならばTRUEを返す。 +*/ +bool item_tester_offer(object_type *o_ptr) +{ + /* Flasks of oil are okay */ + if (o_ptr->tval != TV_CORPSE) return (FALSE); + if (o_ptr->sval != SV_CORPSE) return (FALSE); + + if (my_strchr("pht", r_info[o_ptr->pval].d_char)) return (TRUE); + + /* Assume not okay */ + return (FALSE); +} + +/*! +* @brief 悪魔領域のグレーターデーモン召喚を処理する / Daemon spell Summon Greater Demon +* @return 処理を実行したならばTRUEを返す。 +*/ +bool cast_summon_greater_demon(void) +{ + PLAYER_LEVEL plev = p_ptr->lev; + OBJECT_IDX item; + concptr q, s; + int summon_lev; + object_type *o_ptr; + + item_tester_hook = item_tester_offer; + q = _("どの死体を捧げますか? ", "Sacrifice which corpse? "); + s = _("捧げられる死体を持っていない。", "You have nothing to scrifice."); + o_ptr = choose_object(&item, q, s, (USE_INVEN | USE_FLOOR)); + if (!o_ptr) return FALSE; + + summon_lev = plev * 2 / 3 + r_info[o_ptr->pval].level; + + if (summon_specific(-1, p_ptr->y, p_ptr->x, summon_lev, SUMMON_HI_DEMON, (PM_ALLOW_GROUP | PM_FORCE_PET), '\0')) + { + msg_print(_("硫黄の悪臭が充満した。", "The area fills with a stench of sulphur and brimstone.")); + msg_print(_("「ご用でございますか、ご主人様」", "'What is thy bidding... Master?'")); + + /* Decrease the item (from the pack) */ + if (item >= 0) + { + inven_item_increase(item, -1); + inven_item_describe(item); + inven_item_optimize(item); + } + + /* Decrease the item (from the floor) */ + else + { + floor_item_increase(0 - item, -1); + floor_item_describe(0 - item); + floor_item_optimize(0 - item); + } + } + else + { + msg_print(_("悪魔は現れなかった。", "No Greater Demon arrive.")); + } + + return TRUE; +} + +/*! + * @brief 同族召喚(援軍)処理 + * @param level 召喚基準レベル + * @param y 召喚先Y座標 + * @param x 召喚先X座標 + * @param mode 召喚オプション + * @return ターンを消費した場合TRUEを返す + */ +bool summon_kin_player(DEPTH level, POSITION y, POSITION x, BIT_FLAGS mode) +{ + bool pet = (bool)(mode & PM_FORCE_PET); + SYMBOL_CODE symbol = '\0'; + if (!pet) mode |= PM_NO_PET; + + switch (p_ptr->mimic_form) + { + case MIMIC_NONE: + switch (p_ptr->prace) + { + case RACE_HUMAN: + case RACE_AMBERITE: + case RACE_BARBARIAN: + case RACE_BEASTMAN: + case RACE_DUNADAN: + symbol = 'p'; + break; + case RACE_HALF_ELF: + case RACE_ELF: + case RACE_HOBBIT: + case RACE_GNOME: + case RACE_DWARF: + case RACE_HIGH_ELF: + case RACE_NIBELUNG: + case RACE_DARK_ELF: + case RACE_MIND_FLAYER: + case RACE_KUTAR: + case RACE_S_FAIRY: + symbol = 'h'; + break; + case RACE_HALF_ORC: + symbol = 'o'; + break; + case RACE_HALF_TROLL: + symbol = 'T'; + break; + case RACE_HALF_OGRE: + symbol = 'O'; + break; + case RACE_HALF_GIANT: + case RACE_HALF_TITAN: + case RACE_CYCLOPS: + symbol = 'P'; + break; + case RACE_YEEK: + symbol = 'y'; + break; + case RACE_KLACKON: + symbol = 'K'; + break; + case RACE_KOBOLD: + symbol = 'k'; + break; + case RACE_IMP: + if (one_in_(13)) symbol = 'U'; + else symbol = 'u'; + break; + case RACE_DRACONIAN: + symbol = 'd'; + break; + case RACE_GOLEM: + case RACE_ANDROID: + symbol = 'g'; + break; + case RACE_SKELETON: + if (one_in_(13)) symbol = 'L'; + else symbol = 's'; + break; + case RACE_ZOMBIE: + symbol = 'z'; + break; + case RACE_VAMPIRE: + symbol = 'V'; + break; + case RACE_SPECTRE: + symbol = 'G'; + break; + case RACE_SPRITE: + symbol = 'I'; + break; + case RACE_ENT: + symbol = '#'; + break; + case RACE_ANGEL: + symbol = 'A'; + break; + case RACE_DEMON: + symbol = 'U'; + break; + default: + symbol = 'p'; + break; + } + break; + case MIMIC_DEMON: + if (one_in_(13)) symbol = 'U'; + else symbol = 'u'; + break; + case MIMIC_DEMON_LORD: + symbol = 'U'; + break; + case MIMIC_VAMPIRE: + symbol = 'V'; + break; + } + return summon_specific((pet ? -1 : 0), y, x, level, SUMMON_KIN, mode, symbol); +} + +/*! + * @brief サイバーデーモンの召喚 + * @param who 召喚主のモンスターID(0ならばプレイヤー) + * @param y 召喚位置Y座標 + * @param x 召喚位置X座標 + * @return 作用が実際にあった場合TRUEを返す + */ +int summon_cyber(MONSTER_IDX who, POSITION y, POSITION x) +{ + int i; + int max_cyber = (easy_band ? 1 : (dun_level / 50) + randint1(2)); + int count = 0; + BIT_FLAGS mode = PM_ALLOW_GROUP; + + /* Summoned by a monster */ + if (who > 0) + { + monster_type *m_ptr = &m_list[who]; + if (is_pet(m_ptr)) mode |= PM_FORCE_PET; + } + + if (max_cyber > 4) max_cyber = 4; + + for (i = 0; i < max_cyber; i++) + { + count += summon_specific(who, y, x, 100, SUMMON_CYBER, mode, '\0'); + } + + return count; } \ No newline at end of file diff --git a/src/spells-summon.h b/src/spells-summon.h index 099162366..f5583e88b 100644 --- a/src/spells-summon.h +++ b/src/spells-summon.h @@ -1,13 +1,13 @@ -#pragma once -#include "monster.h" - -extern bool summon_specific(MONSTER_IDX who, POSITION y1, POSITION x1, DEPTH lev, int type, BIT_FLAGS mode, SYMBOL_CODE symbol); -extern bool summon_named_creature(MONSTER_IDX who, POSITION oy, POSITION ox, MONRACE_IDX r_idx, BIT_FLAGS mode); - -extern bool trump_summoning(int num, bool pet, POSITION y, POSITION x, DEPTH lev, int type, BIT_FLAGS mode); -extern bool cast_summon_demon(int power); -extern bool item_tester_offer(object_type *o_ptr); -extern bool cast_summon_greater_demon(void); -extern bool summon_kin_player(DEPTH level, POSITION y, POSITION x, BIT_FLAGS mode); -extern int summon_cyber(MONSTER_IDX who, POSITION y, POSITION x); - +#pragma once +#include "monster.h" + +extern bool summon_specific(MONSTER_IDX who, POSITION y1, POSITION x1, DEPTH lev, int type, BIT_FLAGS mode, SYMBOL_CODE symbol); +extern bool summon_named_creature(MONSTER_IDX who, POSITION oy, POSITION ox, MONRACE_IDX r_idx, BIT_FLAGS mode); + +extern bool trump_summoning(int num, bool pet, POSITION y, POSITION x, DEPTH lev, int type, BIT_FLAGS mode); +extern bool cast_summon_demon(int power); +extern bool item_tester_offer(object_type *o_ptr); +extern bool cast_summon_greater_demon(void); +extern bool summon_kin_player(DEPTH level, POSITION y, POSITION x, BIT_FLAGS mode); +extern int summon_cyber(MONSTER_IDX who, POSITION y, POSITION x); + diff --git a/src/store.h b/src/store.h index 6ae8fa34e..e64b6c5a3 100644 --- a/src/store.h +++ b/src/store.h @@ -1,44 +1,44 @@ - -/* - * Store types - */ -#define STORE_GENERAL 0 /*!< “X•Ü‚ÌŽí—Þ: ŽG‰Ý‰® */ -#define STORE_ARMOURY 1 /*!< “X•Ü‚ÌŽí—Þ: –h‹ï‰® */ -#define STORE_WEAPON 2 /*!< “X•Ü‚ÌŽí—Þ: •Ší‰® */ -#define STORE_TEMPLE 3 /*!< “X•Ü‚ÌŽí—Þ: Ž›‰@ */ -#define STORE_ALCHEMIST 4 /*!< “X•Ü‚ÌŽí—Þ: ˜B‹àp‚Ì“X */ -#define STORE_MAGIC 5 /*!< “X•Ü‚ÌŽí—Þ: –‚“¹‹ï‰® */ -#define STORE_BLACK 6 /*!< “X•Ü‚ÌŽí—Þ: ƒuƒ‰ƒbƒNEƒ}[ƒPƒbƒg */ -#define STORE_HOME 7 /*!< “X•Ü‚ÌŽí—Þ: ‰ä‚ª‰Æ */ -#define STORE_BOOK 8 /*!< “X•Ü‚ÌŽí—Þ: ‘“X */ -#define STORE_MUSEUM 9 /*!< “X•Ü‚ÌŽí—Þ: ”Ž•¨ŠÙ */ -#define MAX_STORES 10 /*!< store.c—p‚Ì“X•Ü‚ÌŽí—ލő吔 / Total number of stores (see "store.c", etc) */ - -#define MAX_OWNERS 32 /*!< Še“X•Ü–ˆ‚Ì“XŽå’è‹`Å‘吔 / Total number of owners per store (see "store.c", etc) */ - - /* - * Store constants - */ -#define STORE_INVEN_MAX 24 /* Max number of discrete objs in inven */ -#define STORE_CHOICES 48 /* Number of items to choose stock from */ -#define STORE_OBJ_LEVEL 5 /* Magic Level for normal stores */ -#define STORE_TURNOVER 9 /* Normal shop turnover, per day */ -#define STORE_MIN_KEEP 6 /* Min slots to "always" keep full */ -#define STORE_MAX_KEEP 18 /* Max slots to "always" keep full */ -#define STORE_SHUFFLE 21 /* 1/Chance (per day) of an owner changing */ -#define STORE_TICKS 1000 /* Number of ticks between turnovers */ - -/* store.c */ -extern bool combine_and_reorder_home(int store_num); -extern void do_cmd_store(void); -extern void store_shuffle(int which); -extern void store_maint(int town_num, int store_num); -extern void store_init(int town_num, int store_num); -extern void move_to_black_market(object_type * o_ptr); - -extern const owner_type owners[MAX_STORES][MAX_OWNERS]; - -extern byte store_table[MAX_STORES][STORE_CHOICES][2]; - - - + +/* + * Store types + */ +#define STORE_GENERAL 0 /*!< 店舗の種類: 雑貨屋 */ +#define STORE_ARMOURY 1 /*!< 店舗の種類: 防具屋 */ +#define STORE_WEAPON 2 /*!< 店舗の種類: 武器屋 */ +#define STORE_TEMPLE 3 /*!< 店舗の種類: 寺院 */ +#define STORE_ALCHEMIST 4 /*!< 店舗の種類: 錬金術の店 */ +#define STORE_MAGIC 5 /*!< 店舗の種類: 魔道具屋 */ +#define STORE_BLACK 6 /*!< 店舗の種類: ブラック・マーケット */ +#define STORE_HOME 7 /*!< 店舗の種類: 我が家 */ +#define STORE_BOOK 8 /*!< 店舗の種類: 書店 */ +#define STORE_MUSEUM 9 /*!< 店舗の種類: 博物館 */ +#define MAX_STORES 10 /*!< store.c用の店舗の種類最大数 / Total number of stores (see "store.c", etc) */ + +#define MAX_OWNERS 32 /*!< 各店舗毎の店主定義最大数 / Total number of owners per store (see "store.c", etc) */ + + /* + * Store constants + */ +#define STORE_INVEN_MAX 24 /* Max number of discrete objs in inven */ +#define STORE_CHOICES 48 /* Number of items to choose stock from */ +#define STORE_OBJ_LEVEL 5 /* Magic Level for normal stores */ +#define STORE_TURNOVER 9 /* Normal shop turnover, per day */ +#define STORE_MIN_KEEP 6 /* Min slots to "always" keep full */ +#define STORE_MAX_KEEP 18 /* Max slots to "always" keep full */ +#define STORE_SHUFFLE 21 /* 1/Chance (per day) of an owner changing */ +#define STORE_TICKS 1000 /* Number of ticks between turnovers */ + +/* store.c */ +extern bool combine_and_reorder_home(int store_num); +extern void do_cmd_store(void); +extern void store_shuffle(int which); +extern void store_maint(int town_num, int store_num); +extern void store_init(int town_num, int store_num); +extern void move_to_black_market(object_type * o_ptr); + +extern const owner_type owners[MAX_STORES][MAX_OWNERS]; + +extern byte store_table[MAX_STORES][STORE_CHOICES][2]; + + + diff --git a/src/trap.c b/src/trap.c index 238975849..44d26e306 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,573 +1,573 @@ -#include "angband.h" -#include "floor.h" -#include "trap.h" -#include "player-damage.h" -#include "projection.h" -#include "spells-summon.h" -#include "quest.h" -#include "artifact.h" - -static s16b normal_traps[MAX_NORMAL_TRAPS]; - - -/*! -* @brief タグに従って、基本トラップテーブルを初期化する / Initialize arrays for normal traps -* @return なし -*/ -void init_normal_traps(void) -{ - int cur_trap = 0; - - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPDOOR"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_PIT"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SPIKED_PIT"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON_PIT"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TY_CURSE"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TELEPORT"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_FIRE"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ACID"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLOW"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_STR"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_DEX"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_CON"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_BLIND"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_CONFUSE"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLEEP"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPS"); - normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ALARM"); -} - -/*! -* @brief 基本トラップをランダムに選択する / -* Get random trap -* @return 選択したトラップのID -* @details -* This routine should be redone to reflect trap "level".\n -* That is, it does not make sense to have spiked pits at 50 feet.\n -* Actually, it is not this routine, but the "trap instantiation"\n -* code, which should also check for "trap doors" on quest levels.\n -*/ -FEAT_IDX choose_random_trap(void) -{ - FEAT_IDX feat; - - /* Pick a trap */ - while (1) - { - /* Hack -- pick a trap */ - feat = normal_traps[randint0(MAX_NORMAL_TRAPS)]; - - /* Accept non-trapdoors */ - if (!have_flag(f_info[feat].flags, FF_MORE)) break; - - /* Hack -- no trap doors on special levels */ - if (p_ptr->inside_arena || quest_number(dun_level)) continue; - - /* Hack -- no trap doors on the deepest level */ - if (dun_level >= d_info[p_ptr->dungeon_idx].maxdepth) continue; - - break; - } - - return feat; -} - -/*! -* @brief マスに存在するトラップを秘匿する / -* Disclose an invisible trap -* @param y 秘匿したいマスのY座標 -* @param x 秘匿したいマスのX座標 -* @return なし -*/ -void disclose_grid(POSITION y, POSITION x) -{ - cave_type *c_ptr = &cave[y][x]; - - if (cave_have_flag_grid(c_ptr, FF_SECRET)) - { - /* No longer hidden */ - cave_alter_feat(y, x, FF_SECRET); - } - else if (c_ptr->mimic) - { - /* No longer hidden */ - c_ptr->mimic = 0; - - note_spot(y, x); - lite_spot(y, x); - } -} - -/*! -* @brief マスをトラップを配置する / -* The location must be a legal, naked, floor grid. -* @param y 配置したいマスのY座標 -* @param x 配置したいマスのX座標 -* @return -* Note that all traps start out as "invisible" and "untyped", and then\n -* when they are "discovered" (by detecting them or setting them off),\n -* the trap is "instantiated" as a visible, "typed", trap.\n -*/ -void place_trap(POSITION y, POSITION x) -{ - cave_type *c_ptr = &cave[y][x]; - - /* Paranoia -- verify location */ - if (!in_bounds(y, x)) return; - - /* Require empty, clean, floor grid */ - if (!cave_clean_bold(y, x)) return; - - /* Place an invisible trap */ - c_ptr->mimic = c_ptr->feat; - c_ptr->feat = choose_random_trap(); -} - - - -/*! -* @brief プレイヤーへのトラップ命中判定 / -* Determine if a trap affects the player. -* @param power 基本回避難度 -* @return トラップが命中した場合TRUEを返す。 -* @details -* Always miss 5% of the time, Always hit 5% of the time. -* Otherwise, match trap power against player armor. -*/ -static int check_hit(int power) -{ - int k; - ARMOUR_CLASS ac; - - /* Percentile dice */ - k = randint0(100); - - /* Hack -- 5% hit, 5% miss */ - if (k < 10) return (k < 5); - - if (p_ptr->pseikaku == SEIKAKU_NAMAKE) - if (one_in_(20)) return (TRUE); - - /* Paranoia -- No power */ - if (power <= 0) return (FALSE); - - /* Total armor */ - ac = p_ptr->ac + p_ptr->to_a; - - /* Power competes against Armor */ - if (randint1(power) > ((ac * 3) / 4)) return (TRUE); - - /* Assume miss */ - return (FALSE); -} - - -/*! -* @brief 落とし穴系トラップの判定とプレイヤーの被害処理 -* @param trap_feat_type トラップの種別ID -* @return なし -*/ -static void hit_trap_pit(int trap_feat_type) -{ - HIT_POINT dam; - concptr trap_name = ""; - concptr spike_name = ""; - - switch (trap_feat_type) - { - case TRAP_PIT: - trap_name = _("落とし穴", "a pit trap"); - break; - case TRAP_SPIKED_PIT: - trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit"); - spike_name = _("スパイク", "spikes"); - break; - case TRAP_POISON_PIT: - trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit"); - spike_name = _("毒を塗られたスパイク", "poisonous spikes"); - break; - default: - return; - } - - if (p_ptr->levitation) - { - msg_format(_("%sを飛び越えた。", "You fly over %s."), trap_name); - return; - } - - msg_format(_("%sに落ちてしまった!", "You have fallen into %s!"), trap_name); - - /* Base damage */ - dam = damroll(2, 6); - - /* Extra spike damage */ - if ((trap_feat_type == TRAP_SPIKED_PIT || trap_feat_type == TRAP_POISON_PIT) && - one_in_(2)) - { - msg_format(_("%sが刺さった!", "You are impaled on %s!"), spike_name); - - dam = dam * 2; - (void)set_cut(p_ptr->cut + randint1(dam)); - - if (trap_feat_type == TRAP_POISON_PIT) { - if (p_ptr->resist_pois || IS_OPPOSE_POIS()) - { - msg_print(_("しかし毒の影響はなかった!", "The poison does not affect you!")); - } - else - { - dam = dam * 2; - (void)set_poisoned(p_ptr->poisoned + randint1(dam)); - } - } - } - - take_hit(DAMAGE_NOESCAPE, dam, trap_name, -1); -} - -/*! -* @brief ダーツ系トラップ(通常ダメージ)の判定とプレイヤーの被害処理 -* @return ダーツが命中した場合TRUEを返す -*/ -static bool hit_trap_dart(void) -{ - bool hit = FALSE; - - if (check_hit(125)) - { - msg_print(_("小さなダーツが飛んできて刺さった!", "A small dart hits you!")); - take_hit(DAMAGE_ATTACK, damroll(1, 4), _("ダーツの罠", "a dart trap"), -1); - if (!CHECK_MULTISHADOW()) hit = TRUE; - } - else - { - msg_print(_("小さなダーツが飛んできた!が、運良く当たらなかった。", "A small dart barely misses you.")); - } - - return hit; -} - -/*! -* @brief ダーツ系トラップ(通常ダメージ+能力値減少)の判定とプレイヤーの被害処理 -* @param stat 低下する能力値ID -* @return なし -*/ -static void hit_trap_lose_stat(int stat) -{ - if (hit_trap_dart()) - { - do_dec_stat(stat); - } -} - -/*! -* @brief ダーツ系トラップ(通常ダメージ+減速)の判定とプレイヤーの被害処理 -* @return なし -*/ -static void hit_trap_slow(void) -{ - if (hit_trap_dart()) - { - set_slow(p_ptr->slow + randint0(20) + 20, FALSE); - } -} - -/*! -* @brief ダーツ系トラップ(通常ダメージ+状態異常)の判定とプレイヤーの被害処理 -* @param trap_message メッセージの補完文字列 -* @param resist 状態異常に抵抗する判定が出たならTRUE -* @param set_status 状態異常を指定する関数ポインタ -* @param turn 状態異常の追加ターン量 -* @return なし -*/ -static void hit_trap_set_abnormal_status(concptr trap_message, bool resist, bool(*set_status)(IDX), IDX turn_aux) -{ - msg_print(trap_message); - if (!resist) - { - set_status(turn_aux); - } -} - -/*! -* @brief プレイヤーへのトラップ作動処理メインルーチン / -* Handle player hitting a real trap -* @param break_trap 作動後のトラップ破壊が確定しているならばTRUE -* @return なし -*/ -void hit_trap(bool break_trap) -{ - int i, num, dam; - POSITION x = p_ptr->x, y = p_ptr->y; - - /* Get the cave grid */ - cave_type *c_ptr = &cave[y][x]; - feature_type *f_ptr = &f_info[c_ptr->feat]; - int trap_feat_type = have_flag(f_ptr->flags, FF_TRAP) ? f_ptr->subtype : NOT_TRAP; - concptr name = _("トラップ", "a trap"); - - disturb(FALSE, TRUE); - - cave_alter_feat(y, x, FF_HIT_TRAP); - - /* Analyze */ - switch (trap_feat_type) - { - case TRAP_TRAPDOOR: - { - if (p_ptr->levitation) - { - msg_print(_("落とし戸を飛び越えた。", "You fly over a trap door.")); - } - else - { - msg_print(_("落とし戸に落ちた!", "You have fallen through a trap door!")); - if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON)) - msg_print(_("くっそ~!", "")); - else if((p_ptr->pseikaku == SEIKAKU_CHARGEMAN)) - msg_print(_("ジュラル星人の仕業に違いない!", "")); - - - sound(SOUND_FALL); - dam = damroll(2, 8); - name = _("落とし戸", "a trap door"); - - take_hit(DAMAGE_NOESCAPE, dam, name, -1); - - /* Still alive and autosave enabled */ - if (autosave_l && (p_ptr->chp >= 0)) - do_cmd_save_game(TRUE); - - do_cmd_write_nikki(NIKKI_BUNSHOU, 0, _("落とし戸に落ちた", "You have fallen through a trap door!")); - prepare_change_floor_mode(CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT); - - /* Leaving */ - p_ptr->leaving = TRUE; - } - break; - } - - case TRAP_PIT: - case TRAP_SPIKED_PIT: - case TRAP_POISON_PIT: - { - hit_trap_pit(trap_feat_type); - break; - } - - case TRAP_TY_CURSE: - { - msg_print(_("何かがピカッと光った!", "There is a flash of shimmering light!")); - num = 2 + randint1(3); - for (i = 0; i < num; i++) - { - (void)summon_specific(0, y, x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0'); - } - - if (dun_level > randint1(100)) /* No nasty effect for low levels */ - { - bool stop_ty = FALSE; - int count = 0; - - do - { - stop_ty = activate_ty_curse(stop_ty, &count); - } while (one_in_(6)); - } - break; - } - - case TRAP_TELEPORT: - { - msg_print(_("テレポート・トラップにひっかかった!", "You hit a teleport trap!")); - teleport_player(100, TELEPORT_PASSIVE); - break; - } - - case TRAP_FIRE: - { - msg_print(_("炎に包まれた!", "You are enveloped in flames!")); - dam = damroll(4, 6); - (void)fire_dam(dam, _("炎のトラップ", "a fire trap"), -1, FALSE); - break; - } - - case TRAP_ACID: - { - msg_print(_("酸が吹きかけられた!", "You are splashed with acid!")); - dam = damroll(4, 6); - (void)acid_dam(dam, _("酸のトラップ", "an acid trap"), -1, FALSE); - break; - } - - case TRAP_SLOW: - { - hit_trap_slow(); - break; - } - - case TRAP_LOSE_STR: - { - hit_trap_lose_stat(A_STR); - break; - } - - case TRAP_LOSE_DEX: - { - hit_trap_lose_stat(A_DEX); - break; - } - - case TRAP_LOSE_CON: - { - hit_trap_lose_stat(A_CON); - break; - } - - case TRAP_BLIND: - { - hit_trap_set_abnormal_status( - _("黒いガスに包み込まれた!", "A black gas surrounds you!"), - p_ptr->resist_blind, - set_blind, p_ptr->blind + (TIME_EFFECT)randint0(50) + 25); - break; - } - - case TRAP_CONFUSE: - { - hit_trap_set_abnormal_status( - _("きらめくガスに包み込まれた!", "A gas of scintillating colors surrounds you!"), - p_ptr->resist_conf, - set_confused, p_ptr->confused + (TIME_EFFECT)randint0(20) + 10); - break; - } - - case TRAP_POISON: - { - hit_trap_set_abnormal_status( - _("刺激的な緑色のガスに包み込まれた!", "A pungent green gas surrounds you!"), - p_ptr->resist_pois || IS_OPPOSE_POIS(), - set_poisoned, p_ptr->poisoned + (TIME_EFFECT)randint0(20) + 10); - break; - } - - case TRAP_SLEEP: - { - msg_print(_("奇妙な白い霧に包まれた!", "A strange white mist surrounds you!")); - if (!p_ptr->free_act) - { - msg_print(_("あなたは眠りに就いた。", "You fall asleep.")); - - if (ironman_nightmare) - { - msg_print(_("身の毛もよだつ光景が頭に浮かんだ。", "A horrible vision enters your mind.")); - - /* Have some nightmares */ - sanity_blast(NULL, FALSE); - - } - (void)set_paralyzed(p_ptr->paralyzed + randint0(10) + 5); - } - break; - } - - case TRAP_TRAPS: - { - msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!")); - /* Make some new traps */ - project(0, 1, y, x, 0, GF_MAKE_TRAP, PROJECT_HIDE | PROJECT_JUMP | PROJECT_GRID, -1); - - break; - } - - case TRAP_ALARM: - { - msg_print(_("けたたましい音が鳴り響いた!", "An alarm sounds!")); - - aggravate_monsters(0); - - break; - } - - case TRAP_OPEN: - { - msg_print(_("大音響と共にまわりの壁が崩れた!", "Suddenly, surrounding walls are opened!")); - (void)project(0, 3, y, x, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); - (void)project(0, 3, y, x - 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); - (void)project(0, 3, y, x + 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); - aggravate_monsters(0); - - break; - } - - case TRAP_ARMAGEDDON: - { - static int levs[10] = { 0, 0, 20, 10, 5, 3, 2, 1, 1, 1 }; - int evil_idx = 0, good_idx = 0; - - DEPTH lev; - msg_print(_("突然天界の戦争に巻き込まれた!", "Suddenly, you are surrounded by immotal beings!")); - - /* Summon Demons and Angels */ - for (lev = dun_level; lev >= 20; lev -= 1 + lev / 16) - { - num = levs[MIN(lev / 10, 9)]; - for (i = 0; i < num; i++) - { - POSITION x1 = rand_spread(x, 7); - POSITION y1 = rand_spread(y, 5); - - /* Skip illegal grids */ - if (!in_bounds(y1, x1)) continue; - - /* Require line of projection */ - if (!projectable(p_ptr->y, p_ptr->x, y1, x1)) continue; - - if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_EVIL, (PM_NO_PET), '\0')) - evil_idx = hack_m_idx_ii; - - if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_GOOD, (PM_NO_PET), '\0')) - { - good_idx = hack_m_idx_ii; - } - - /* Let them fight each other */ - if (evil_idx && good_idx) - { - monster_type *evil_ptr = &m_list[evil_idx]; - monster_type *good_ptr = &m_list[good_idx]; - evil_ptr->target_y = good_ptr->fy; - evil_ptr->target_x = good_ptr->fx; - good_ptr->target_y = evil_ptr->fy; - good_ptr->target_x = evil_ptr->fx; - } - } - } - break; - } - - case TRAP_PIRANHA: - { - msg_print(_("突然壁から水が溢れ出した!ピラニアがいる!", "Suddenly, the room is filled with water with piranhas!")); - - /* Water fills room */ - fire_ball_hide(GF_WATER_FLOW, 0, 1, 10); - - /* Summon Piranhas */ - num = 1 + dun_level / 20; - for (i = 0; i < num; i++) - { - (void)summon_specific(0, y, x, dun_level, SUMMON_PIRANHAS, (PM_ALLOW_GROUP | PM_NO_PET), '\0'); - } - break; - } - } - - if (break_trap && is_trap(c_ptr->feat)) - { - cave_alter_feat(y, x, FF_DISARM); - msg_print(_("トラップを粉砕した。", "You destroyed the trap.")); - } -} +#include "angband.h" +#include "floor.h" +#include "trap.h" +#include "player-damage.h" +#include "projection.h" +#include "spells-summon.h" +#include "quest.h" +#include "artifact.h" + +static s16b normal_traps[MAX_NORMAL_TRAPS]; + + +/*! +* @brief タグに従って、基本トラップテーブルを初期化する / Initialize arrays for normal traps +* @return なし +*/ +void init_normal_traps(void) +{ + int cur_trap = 0; + + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPDOOR"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_PIT"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SPIKED_PIT"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON_PIT"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TY_CURSE"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TELEPORT"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_FIRE"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ACID"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLOW"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_STR"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_DEX"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_CON"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_BLIND"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_CONFUSE"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLEEP"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPS"); + normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ALARM"); +} + +/*! +* @brief 基本トラップをランダムに選択する / +* Get random trap +* @return 選択したトラップのID +* @details +* This routine should be redone to reflect trap "level".\n +* That is, it does not make sense to have spiked pits at 50 feet.\n +* Actually, it is not this routine, but the "trap instantiation"\n +* code, which should also check for "trap doors" on quest levels.\n +*/ +FEAT_IDX choose_random_trap(void) +{ + FEAT_IDX feat; + + /* Pick a trap */ + while (1) + { + /* Hack -- pick a trap */ + feat = normal_traps[randint0(MAX_NORMAL_TRAPS)]; + + /* Accept non-trapdoors */ + if (!have_flag(f_info[feat].flags, FF_MORE)) break; + + /* Hack -- no trap doors on special levels */ + if (p_ptr->inside_arena || quest_number(dun_level)) continue; + + /* Hack -- no trap doors on the deepest level */ + if (dun_level >= d_info[p_ptr->dungeon_idx].maxdepth) continue; + + break; + } + + return feat; +} + +/*! +* @brief マスに存在するトラップを秘匿する / +* Disclose an invisible trap +* @param y 秘匿したいマスのY座標 +* @param x 秘匿したいマスのX座標 +* @return なし +*/ +void disclose_grid(POSITION y, POSITION x) +{ + cave_type *c_ptr = &cave[y][x]; + + if (cave_have_flag_grid(c_ptr, FF_SECRET)) + { + /* No longer hidden */ + cave_alter_feat(y, x, FF_SECRET); + } + else if (c_ptr->mimic) + { + /* No longer hidden */ + c_ptr->mimic = 0; + + note_spot(y, x); + lite_spot(y, x); + } +} + +/*! +* @brief マスをトラップを配置する / +* The location must be a legal, naked, floor grid. +* @param y 配置したいマスのY座標 +* @param x 配置したいマスのX座標 +* @return +* Note that all traps start out as "invisible" and "untyped", and then\n +* when they are "discovered" (by detecting them or setting them off),\n +* the trap is "instantiated" as a visible, "typed", trap.\n +*/ +void place_trap(POSITION y, POSITION x) +{ + cave_type *c_ptr = &cave[y][x]; + + /* Paranoia -- verify location */ + if (!in_bounds(y, x)) return; + + /* Require empty, clean, floor grid */ + if (!cave_clean_bold(y, x)) return; + + /* Place an invisible trap */ + c_ptr->mimic = c_ptr->feat; + c_ptr->feat = choose_random_trap(); +} + + + +/*! +* @brief プレイヤーへのトラップ命中判定 / +* Determine if a trap affects the player. +* @param power 基本回避難度 +* @return トラップが命中した場合TRUEを返す。 +* @details +* Always miss 5% of the time, Always hit 5% of the time. +* Otherwise, match trap power against player armor. +*/ +static int check_hit(int power) +{ + int k; + ARMOUR_CLASS ac; + + /* Percentile dice */ + k = randint0(100); + + /* Hack -- 5% hit, 5% miss */ + if (k < 10) return (k < 5); + + if (p_ptr->pseikaku == SEIKAKU_NAMAKE) + if (one_in_(20)) return (TRUE); + + /* Paranoia -- No power */ + if (power <= 0) return (FALSE); + + /* Total armor */ + ac = p_ptr->ac + p_ptr->to_a; + + /* Power competes against Armor */ + if (randint1(power) > ((ac * 3) / 4)) return (TRUE); + + /* Assume miss */ + return (FALSE); +} + + +/*! +* @brief 落とし穴系トラップの判定とプレイヤーの被害処理 +* @param trap_feat_type トラップの種別ID +* @return なし +*/ +static void hit_trap_pit(int trap_feat_type) +{ + HIT_POINT dam; + concptr trap_name = ""; + concptr spike_name = ""; + + switch (trap_feat_type) + { + case TRAP_PIT: + trap_name = _("落とし穴", "a pit trap"); + break; + case TRAP_SPIKED_PIT: + trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit"); + spike_name = _("スパイク", "spikes"); + break; + case TRAP_POISON_PIT: + trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit"); + spike_name = _("毒を塗られたスパイク", "poisonous spikes"); + break; + default: + return; + } + + if (p_ptr->levitation) + { + msg_format(_("%sを飛び越えた。", "You fly over %s."), trap_name); + return; + } + + msg_format(_("%sに落ちてしまった!", "You have fallen into %s!"), trap_name); + + /* Base damage */ + dam = damroll(2, 6); + + /* Extra spike damage */ + if ((trap_feat_type == TRAP_SPIKED_PIT || trap_feat_type == TRAP_POISON_PIT) && + one_in_(2)) + { + msg_format(_("%sが刺さった!", "You are impaled on %s!"), spike_name); + + dam = dam * 2; + (void)set_cut(p_ptr->cut + randint1(dam)); + + if (trap_feat_type == TRAP_POISON_PIT) { + if (p_ptr->resist_pois || IS_OPPOSE_POIS()) + { + msg_print(_("しかし毒の影響はなかった!", "The poison does not affect you!")); + } + else + { + dam = dam * 2; + (void)set_poisoned(p_ptr->poisoned + randint1(dam)); + } + } + } + + take_hit(DAMAGE_NOESCAPE, dam, trap_name, -1); +} + +/*! +* @brief ダーツ系トラップ(通常ダメージ)の判定とプレイヤーの被害処理 +* @return ダーツが命中した場合TRUEを返す +*/ +static bool hit_trap_dart(void) +{ + bool hit = FALSE; + + if (check_hit(125)) + { + msg_print(_("小さなダーツが飛んできて刺さった!", "A small dart hits you!")); + take_hit(DAMAGE_ATTACK, damroll(1, 4), _("ダーツの罠", "a dart trap"), -1); + if (!CHECK_MULTISHADOW()) hit = TRUE; + } + else + { + msg_print(_("小さなダーツが飛んできた!が、運良く当たらなかった。", "A small dart barely misses you.")); + } + + return hit; +} + +/*! +* @brief ダーツ系トラップ(通常ダメージ+能力値減少)の判定とプレイヤーの被害処理 +* @param stat 低下する能力値ID +* @return なし +*/ +static void hit_trap_lose_stat(int stat) +{ + if (hit_trap_dart()) + { + do_dec_stat(stat); + } +} + +/*! +* @brief ダーツ系トラップ(通常ダメージ+減速)の判定とプレイヤーの被害処理 +* @return なし +*/ +static void hit_trap_slow(void) +{ + if (hit_trap_dart()) + { + set_slow(p_ptr->slow + randint0(20) + 20, FALSE); + } +} + +/*! +* @brief ダーツ系トラップ(通常ダメージ+状態異常)の判定とプレイヤーの被害処理 +* @param trap_message メッセージの補完文字列 +* @param resist 状態異常に抵抗する判定が出たならTRUE +* @param set_status 状態異常を指定する関数ポインタ +* @param turn 状態異常の追加ターン量 +* @return なし +*/ +static void hit_trap_set_abnormal_status(concptr trap_message, bool resist, bool(*set_status)(IDX), IDX turn_aux) +{ + msg_print(trap_message); + if (!resist) + { + set_status(turn_aux); + } +} + +/*! +* @brief プレイヤーへのトラップ作動処理メインルーチン / +* Handle player hitting a real trap +* @param break_trap 作動後のトラップ破壊が確定しているならばTRUE +* @return なし +*/ +void hit_trap(bool break_trap) +{ + int i, num, dam; + POSITION x = p_ptr->x, y = p_ptr->y; + + /* Get the cave grid */ + cave_type *c_ptr = &cave[y][x]; + feature_type *f_ptr = &f_info[c_ptr->feat]; + int trap_feat_type = have_flag(f_ptr->flags, FF_TRAP) ? f_ptr->subtype : NOT_TRAP; + concptr name = _("トラップ", "a trap"); + + disturb(FALSE, TRUE); + + cave_alter_feat(y, x, FF_HIT_TRAP); + + /* Analyze */ + switch (trap_feat_type) + { + case TRAP_TRAPDOOR: + { + if (p_ptr->levitation) + { + msg_print(_("落とし戸を飛び越えた。", "You fly over a trap door.")); + } + else + { + msg_print(_("落とし戸に落ちた!", "You have fallen through a trap door!")); + if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON)) + msg_print(_("くっそ~!", "")); + else if((p_ptr->pseikaku == SEIKAKU_CHARGEMAN)) + msg_print(_("ジュラル星人の仕業に違いない!", "")); + + + sound(SOUND_FALL); + dam = damroll(2, 8); + name = _("落とし戸", "a trap door"); + + take_hit(DAMAGE_NOESCAPE, dam, name, -1); + + /* Still alive and autosave enabled */ + if (autosave_l && (p_ptr->chp >= 0)) + do_cmd_save_game(TRUE); + + do_cmd_write_nikki(NIKKI_BUNSHOU, 0, _("落とし戸に落ちた", "You have fallen through a trap door!")); + prepare_change_floor_mode(CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT); + + /* Leaving */ + p_ptr->leaving = TRUE; + } + break; + } + + case TRAP_PIT: + case TRAP_SPIKED_PIT: + case TRAP_POISON_PIT: + { + hit_trap_pit(trap_feat_type); + break; + } + + case TRAP_TY_CURSE: + { + msg_print(_("何かがピカッと光った!", "There is a flash of shimmering light!")); + num = 2 + randint1(3); + for (i = 0; i < num; i++) + { + (void)summon_specific(0, y, x, dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0'); + } + + if (dun_level > randint1(100)) /* No nasty effect for low levels */ + { + bool stop_ty = FALSE; + int count = 0; + + do + { + stop_ty = activate_ty_curse(stop_ty, &count); + } while (one_in_(6)); + } + break; + } + + case TRAP_TELEPORT: + { + msg_print(_("テレポート・トラップにひっかかった!", "You hit a teleport trap!")); + teleport_player(100, TELEPORT_PASSIVE); + break; + } + + case TRAP_FIRE: + { + msg_print(_("炎に包まれた!", "You are enveloped in flames!")); + dam = damroll(4, 6); + (void)fire_dam(dam, _("炎のトラップ", "a fire trap"), -1, FALSE); + break; + } + + case TRAP_ACID: + { + msg_print(_("酸が吹きかけられた!", "You are splashed with acid!")); + dam = damroll(4, 6); + (void)acid_dam(dam, _("酸のトラップ", "an acid trap"), -1, FALSE); + break; + } + + case TRAP_SLOW: + { + hit_trap_slow(); + break; + } + + case TRAP_LOSE_STR: + { + hit_trap_lose_stat(A_STR); + break; + } + + case TRAP_LOSE_DEX: + { + hit_trap_lose_stat(A_DEX); + break; + } + + case TRAP_LOSE_CON: + { + hit_trap_lose_stat(A_CON); + break; + } + + case TRAP_BLIND: + { + hit_trap_set_abnormal_status( + _("黒いガスに包み込まれた!", "A black gas surrounds you!"), + p_ptr->resist_blind, + set_blind, p_ptr->blind + (TIME_EFFECT)randint0(50) + 25); + break; + } + + case TRAP_CONFUSE: + { + hit_trap_set_abnormal_status( + _("きらめくガスに包み込まれた!", "A gas of scintillating colors surrounds you!"), + p_ptr->resist_conf, + set_confused, p_ptr->confused + (TIME_EFFECT)randint0(20) + 10); + break; + } + + case TRAP_POISON: + { + hit_trap_set_abnormal_status( + _("刺激的な緑色のガスに包み込まれた!", "A pungent green gas surrounds you!"), + p_ptr->resist_pois || IS_OPPOSE_POIS(), + set_poisoned, p_ptr->poisoned + (TIME_EFFECT)randint0(20) + 10); + break; + } + + case TRAP_SLEEP: + { + msg_print(_("奇妙な白い霧に包まれた!", "A strange white mist surrounds you!")); + if (!p_ptr->free_act) + { + msg_print(_("あなたは眠りに就いた。", "You fall asleep.")); + + if (ironman_nightmare) + { + msg_print(_("身の毛もよだつ光景が頭に浮かんだ。", "A horrible vision enters your mind.")); + + /* Have some nightmares */ + sanity_blast(NULL, FALSE); + + } + (void)set_paralyzed(p_ptr->paralyzed + randint0(10) + 5); + } + break; + } + + case TRAP_TRAPS: + { + msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!")); + /* Make some new traps */ + project(0, 1, y, x, 0, GF_MAKE_TRAP, PROJECT_HIDE | PROJECT_JUMP | PROJECT_GRID, -1); + + break; + } + + case TRAP_ALARM: + { + msg_print(_("けたたましい音が鳴り響いた!", "An alarm sounds!")); + + aggravate_monsters(0); + + break; + } + + case TRAP_OPEN: + { + msg_print(_("大音響と共にまわりの壁が崩れた!", "Suddenly, surrounding walls are opened!")); + (void)project(0, 3, y, x, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); + (void)project(0, 3, y, x - 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); + (void)project(0, 3, y, x + 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1); + aggravate_monsters(0); + + break; + } + + case TRAP_ARMAGEDDON: + { + static int levs[10] = { 0, 0, 20, 10, 5, 3, 2, 1, 1, 1 }; + int evil_idx = 0, good_idx = 0; + + DEPTH lev; + msg_print(_("突然天界の戦争に巻き込まれた!", "Suddenly, you are surrounded by immotal beings!")); + + /* Summon Demons and Angels */ + for (lev = dun_level; lev >= 20; lev -= 1 + lev / 16) + { + num = levs[MIN(lev / 10, 9)]; + for (i = 0; i < num; i++) + { + POSITION x1 = rand_spread(x, 7); + POSITION y1 = rand_spread(y, 5); + + /* Skip illegal grids */ + if (!in_bounds(y1, x1)) continue; + + /* Require line of projection */ + if (!projectable(p_ptr->y, p_ptr->x, y1, x1)) continue; + + if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_EVIL, (PM_NO_PET), '\0')) + evil_idx = hack_m_idx_ii; + + if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_GOOD, (PM_NO_PET), '\0')) + { + good_idx = hack_m_idx_ii; + } + + /* Let them fight each other */ + if (evil_idx && good_idx) + { + monster_type *evil_ptr = &m_list[evil_idx]; + monster_type *good_ptr = &m_list[good_idx]; + evil_ptr->target_y = good_ptr->fy; + evil_ptr->target_x = good_ptr->fx; + good_ptr->target_y = evil_ptr->fy; + good_ptr->target_x = evil_ptr->fx; + } + } + } + break; + } + + case TRAP_PIRANHA: + { + msg_print(_("突然壁から水が溢れ出した!ピラニアがいる!", "Suddenly, the room is filled with water with piranhas!")); + + /* Water fills room */ + fire_ball_hide(GF_WATER_FLOW, 0, 1, 10); + + /* Summon Piranhas */ + num = 1 + dun_level / 20; + for (i = 0; i < num; i++) + { + (void)summon_specific(0, y, x, dun_level, SUMMON_PIRANHAS, (PM_ALLOW_GROUP | PM_NO_PET), '\0'); + } + break; + } + } + + if (break_trap && is_trap(c_ptr->feat)) + { + cave_alter_feat(y, x, FF_DISARM); + msg_print(_("トラップを粉砕した。", "You destroyed the trap.")); + } +} diff --git a/src/trap.h b/src/trap.h index ef8ad56fa..f6da986ea 100644 --- a/src/trap.h +++ b/src/trap.h @@ -1,40 +1,40 @@ - -extern void init_normal_traps(void); -extern FEAT_IDX choose_random_trap(void); -extern void disclose_grid(POSITION y, POSITION x); -extern void place_trap(POSITION y, POSITION x); -extern void hit_trap(bool break_trap); - -/* Types of normal traps */ -#define NOT_TRAP -1 -#define TRAP_TRAPDOOR 0 -#define TRAP_PIT 1 -#define TRAP_SPIKED_PIT 2 -#define TRAP_POISON_PIT 3 -#define TRAP_TY_CURSE 4 -#define TRAP_TELEPORT 5 -#define TRAP_FIRE 6 -#define TRAP_ACID 7 -#define TRAP_SLOW 8 - -#define TRAP_LOSE_STR 9 -#define TRAP_LOSE_DEX 10 -#define TRAP_LOSE_CON 11 -#define TRAP_BLIND 12 -#define TRAP_CONFUSE 13 -#define TRAP_POISON 14 -#define TRAP_SLEEP 15 -#define TRAP_TRAPS 16 -#define TRAP_ALARM 17 - -#define MAX_NORMAL_TRAPS 18 - - -/* Types of special traps */ -#define TRAP_OPEN 18 -#define TRAP_ARMAGEDDON 19 -#define TRAP_PIRANHA 20 - - - -/* See init_feat_variables() in init2.c */ + +extern void init_normal_traps(void); +extern FEAT_IDX choose_random_trap(void); +extern void disclose_grid(POSITION y, POSITION x); +extern void place_trap(POSITION y, POSITION x); +extern void hit_trap(bool break_trap); + +/* Types of normal traps */ +#define NOT_TRAP -1 +#define TRAP_TRAPDOOR 0 +#define TRAP_PIT 1 +#define TRAP_SPIKED_PIT 2 +#define TRAP_POISON_PIT 3 +#define TRAP_TY_CURSE 4 +#define TRAP_TELEPORT 5 +#define TRAP_FIRE 6 +#define TRAP_ACID 7 +#define TRAP_SLOW 8 + +#define TRAP_LOSE_STR 9 +#define TRAP_LOSE_DEX 10 +#define TRAP_LOSE_CON 11 +#define TRAP_BLIND 12 +#define TRAP_CONFUSE 13 +#define TRAP_POISON 14 +#define TRAP_SLEEP 15 +#define TRAP_TRAPS 16 +#define TRAP_ALARM 17 + +#define MAX_NORMAL_TRAPS 18 + + +/* Types of special traps */ +#define TRAP_OPEN 18 +#define TRAP_ARMAGEDDON 19 +#define TRAP_PIRANHA 20 + + + +/* See init_feat_variables() in init2.c */ diff --git a/src/world.c b/src/world.c index b335b9e54..0b49c2610 100644 --- a/src/world.c +++ b/src/world.c @@ -1,43 +1,43 @@ -#include "angband.h" - -/*! - * @brief ゲーム時間が日中かどうかを返す / - * Whether daytime or not - * @return 日中ならばTRUE、夜ならばFALSE - */ -bool is_daytime(void) -{ - s32b len = TURNS_PER_TICK * TOWN_DAWN; - if ((turn % len) < (len / 2)) - return TRUE; - else - return FALSE; -} - -/*! - * @brief 現在の日数、時刻を返す / - * Extract day, hour, min - * @param day 日数を返すための参照ポインタ - * @param hour 時数を返すための参照ポインタ - * @param min 分数を返すための参照ポインタ - */ -void extract_day_hour_min(int *day, int *hour, int *min) -{ - const s32b A_DAY = TURNS_PER_TICK * TOWN_DAWN; - s32b turn_in_today = (turn + A_DAY / 4) % A_DAY; - - switch (p_ptr->start_race) - { - case RACE_VAMPIRE: - case RACE_SKELETON: - case RACE_ZOMBIE: - case RACE_SPECTRE: - *day = (turn - A_DAY * 3 / 4) / A_DAY + 1; - break; - default: - *day = (turn + A_DAY / 4) / A_DAY + 1; - break; - } - *hour = (24 * turn_in_today / A_DAY) % 24; - *min = (1440 * turn_in_today / A_DAY) % 60; -} +#include "angband.h" + +/*! + * @brief ゲーム時間が日中かどうかを返す / + * Whether daytime or not + * @return 日中ならばTRUE、夜ならばFALSE + */ +bool is_daytime(void) +{ + s32b len = TURNS_PER_TICK * TOWN_DAWN; + if ((turn % len) < (len / 2)) + return TRUE; + else + return FALSE; +} + +/*! + * @brief 現在の日数、時刻を返す / + * Extract day, hour, min + * @param day 日数を返すための参照ポインタ + * @param hour 時数を返すための参照ポインタ + * @param min 分数を返すための参照ポインタ + */ +void extract_day_hour_min(int *day, int *hour, int *min) +{ + const s32b A_DAY = TURNS_PER_TICK * TOWN_DAWN; + s32b turn_in_today = (turn + A_DAY / 4) % A_DAY; + + switch (p_ptr->start_race) + { + case RACE_VAMPIRE: + case RACE_SKELETON: + case RACE_ZOMBIE: + case RACE_SPECTRE: + *day = (turn - A_DAY * 3 / 4) / A_DAY + 1; + break; + default: + *day = (turn + A_DAY / 4) / A_DAY + 1; + break; + } + *hour = (24 * turn_in_today / A_DAY) % 24; + *min = (1440 * turn_in_today / A_DAY) % 60; +} diff --git a/src/world.h b/src/world.h index 1cde2fc7d..96ac405e6 100644 --- a/src/world.h +++ b/src/world.h @@ -1,2 +1,2 @@ -extern bool is_daytime(void); -extern void extract_day_hour_min(int *day, int *hour, int *min); +extern bool is_daytime(void); +extern void extract_day_hour_min(int *day, int *hour, int *min); -- 2.11.0