Index: src/store.c =================================================================== --- src/store.c (revision 2930) +++ src/store.c (working copy) @@ -12,6 +12,7 @@ #include "angband.h" +void itemset_main_process(s16b command_cmd); #ifdef JP /* 下の方から移動してきました */ @@ -4402,6 +4403,24 @@ break; } + /* アイテムセット */ + case '1': + case '2': + case '3': + case '4': + case ',': /* '5' command */ + case '6': + case '7': + case '8': + case '9': + { + if (cur_store_num == STORE_HOME) + { + itemset_main_process(command_cmd); + } + break; + } + /* 日本語版追加 */ /* 1 ページ戻るコマンド: 我が家のページ数が多いので重宝するはず By BUG */ case '-': @@ -4742,11 +4761,14 @@ } else { + /* アイテムセットで1-9を使うときに、移動用に自動で入力される';'を無視 */ + if (command_cmd != ';') { #ifdef JP msg_print("そのコマンドは店の中では使えません。"); #else msg_print("That command does not work in stores."); #endif + } } break; @@ -4906,10 +4928,12 @@ prt("g) アイテムを取る", 21, 27); prt("d) アイテムを置く", 22, 27); prt("x) 家のアイテムを調べる", 23,27); + prt("1-9) アイテムセット", 23, 56); #else prt("g) Get an item.", 21, 27); prt("d) Drop an item.", 22, 27); prt("x) eXamine an item in the home.", 23,27); + prt("1-9) Item set", 23, 56); #endif } @@ -5361,3 +5385,675 @@ object_wipe(o_ptr); /* Don't leave a bogus object behind... */ } + + +/* ------------------------------------------------------------------------------------------ */ +/* アイテムセット */ +/* ------------------------------------------------------------------------------------------ */ +extern bool save_itemset(char *name); +extern bool load_itemset(char *name, object_type *itemset_ptr, int *itemset_len_ptr); + +/* + * Display the itemset. + */ +int show_itemset(int target_item, object_type *itemset) +{ + int i, j, k, l, z = 0; + int col, cur_col, len; + object_type *o_ptr; + char o_name[MAX_NLEN]; + char tmp_val[80]; + int out_index[23]; + byte out_color[23]; + char out_desc[23][MAX_NLEN]; + int target_item_label = 0; + int wid, hgt; + char inven_label[52 + 1]; + + /* Starting column */ + col = command_gap; + + /* Get size */ + Term_get_size(&wid, &hgt); + + /* Default "max-length" */ + len = wid - col - 1; + + + /* Find the "final" slot */ + for (i = 0; i < INVEN_PACK; i++) + { + o_ptr = &itemset[i]; + + /* Skip non-objects */ + if (!o_ptr->k_idx) continue; + + /* Track */ + z = i + 1; + } + + strcpy(inven_label, "abcdefghijklmnopqrstuvwxyz"); + + /* Display the inventory */ + for (k = 0, i = 0; i < z; i++) + { + o_ptr = &itemset[i]; + + /* Is this item acceptable? */ + if (!item_tester_okay(o_ptr)) continue; + + /* Describe the object */ + object_desc(o_name, o_ptr, 0); + if (!object_is_aware(o_ptr)) { +#ifdef JP + o_name = "未知のアイテム"; +#else + o_name = "unidentified item"; +#endif + } + + /* Save the object index, color, and description */ + out_index[k] = i; + out_color[k] = tval_to_attr[o_ptr->tval % 128]; + + /* Grey out charging items */ + if (o_ptr->timeout) + { + out_color[k] = TERM_L_DARK; + } + + (void)strcpy(out_desc[k], o_name); + + /* Find the predicted "line length" */ + l = strlen(out_desc[k]) + 5; + + /* Be sure to account for the weight */ + if (show_weights) l += 9; + + /* Account for icon if displayed */ + if (show_item_graph) + { + l += 2; + if (use_bigtile) l++; + } + + /* Maintain the maximum length */ + if (l > len) len = l; + + /* Advance to next "line" */ + k++; + } + + /* Find the column to start in */ + col = (len > wid - 4) ? 0 : (wid - len - 1); + + /* Output each entry */ + for (j = 0; j < k; j++) + { + /* Get the index */ + i = out_index[j]; + + /* Get the item */ + o_ptr = &itemset[i]; + + /* Clear the line */ + prt("", j + 1, col ? col - 2 : col); + + if (use_menu && target_item) + { + if (j == (target_item-1)) + { +#ifdef JP + strcpy(tmp_val, "》"); +#else + strcpy(tmp_val, "> "); +#endif + target_item_label = i; + } + else strcpy(tmp_val, " "); + } + else if (i <= INVEN_PACK) + { + /* Prepare an index --(-- */ + sprintf(tmp_val, "%c)", inven_label[i]); + } + else + { + /* Prepare an index --(-- */ + sprintf(tmp_val, "%c)", index_to_label(i)); + } + + /* Clear the line with the (possibly indented) index */ + put_str(tmp_val, j + 1, col); + + cur_col = col + 3; + + /* Display graphics for object, if desired */ + if (show_item_graph) + { + byte a = object_attr(o_ptr); + char c = object_char(o_ptr); + +#ifdef AMIGA + if (a & 0x80) a |= 0x40; +#endif + + Term_queue_bigchar(cur_col, j + 1, a, c, 0, 0); + if (use_bigtile) cur_col++; + + cur_col += 2; + } + + + /* Display the entry itself */ + c_put_str(out_color[j], out_desc[j], j + 1, cur_col); + + /* Display the weight if needed */ + if (show_weights) + { + int wgt = o_ptr->weight * o_ptr->number; +#ifdef JP + (void)sprintf(tmp_val, "%3d.%1d kg", lbtokg1(wgt) , lbtokg2(wgt) ); +#else + (void)sprintf(tmp_val, "%3d.%1d lb", wgt / 10, wgt % 10); +#endif + + prt(tmp_val, j + 1, wid - 9); + } + } + + /* Make a "shadow" below the list (only if needed) */ + if (j && (j < 23)) prt("", j + 1, col ? col - 2 : col); + + /* Save the new column */ + command_gap = col; + + return target_item_label; +} + +/* メッセージ表示・入力無しで、我が家からアイテムを取り出す */ +static bool home_purchase_silent(int item, int wish_amt) +{ + bool result = TRUE; + + int i; + int amt; + int item_new; + + object_type forge; + object_type *j_ptr; + + object_type *o_ptr; + + char o_name[MAX_NLEN]; + + /* Get the actual item */ + o_ptr = &st_ptr->stock[item]; + + /* Assume the player wants just one of them */ + amt = 1; + + /* Get local object */ + j_ptr = &forge; + + /* Get a copy of the object */ + object_copy(j_ptr, o_ptr); + + /* + * If a rod or wand, allocate total maximum timeouts or charges + * between those purchased and left on the shelf. + */ + reduce_charges(j_ptr, o_ptr->number - amt); + + /* Modify quantity */ + j_ptr->number = amt; + + /* Hack -- require room in pack */ + if (!inven_carry_okay(j_ptr)) + { + /* +#ifdef JP + msg_print("そんなにアイテムを持てない。"); +#else + msg_print("You cannot carry that many different items."); +#endif + */ + return FALSE; + } + + /* 指定数ほど取れない場合は、取れるだけ取る */ + if (o_ptr->number >= wish_amt) { + amt = wish_amt; + } else { + amt = o_ptr->number; + result = FALSE; + } + + /* Get local object */ + j_ptr = &forge; + + /* Get desired object */ + object_copy(j_ptr, o_ptr); + + /* + * If a rod or wand, allocate total maximum timeouts or charges + * between those purchased and left on the shelf. + */ + reduce_charges(j_ptr, o_ptr->number - amt); + + /* Modify quantity */ + j_ptr->number = amt; + + /* Hack -- require room in pack */ + if (!inven_carry_okay(j_ptr)) + { + /* +#ifdef JP + msg_print("ザックにそのアイテムを入れる隙間がない。"); +#else + msg_print("You cannot carry that many items."); +#endif + */ + return FALSE; + } + + /* Home is much easier */ + { + bool combined_or_reordered; + + /* Distribute charges of wands/rods */ + distribute_charges(o_ptr, j_ptr, amt); + + /* Give it to the player */ + item_new = inven_carry(j_ptr); + + /* Describe just the result */ + object_desc(o_name, &inventory[item_new], 0); + + /* Message */ + /* +#ifdef JP + msg_format("%s(%c)を取った。", +#else + msg_format("You have %s (%c).", +#endif + o_name, index_to_label(item_new)); + */ + + /* Handle stuff */ + handle_stuff(); + + /* Take note if we take the last one */ + i = st_ptr->stock_num; + + /* Remove the items from the home */ + store_item_increase(item, -amt); + store_item_optimize(item); + + combined_or_reordered = combine_and_reorder_home(STORE_HOME); + + /* Hack -- Item is still here */ + if (i == st_ptr->stock_num) + { + /* Redraw everything */ + if (combined_or_reordered) display_inventory(); + + /* Redraw the item */ + else display_entry(item); + } + + /* The item is gone */ + else + { + /* Nothing left */ + if (st_ptr->stock_num == 0) store_top = 0; + + /* Nothing left on that screen */ + else if (store_top >= st_ptr->stock_num) store_top -= 12; + + /* Redraw everything */ + display_inventory(); + + chg_virtue(V_SACRIFICE, 1); + } + } + + return result; +} + +/* メッセージ表示・入力無しで、我が家にアイテムを置く */ +/* いくつかのアイテムを持っている場合、全部を置く */ +static void home_sell_silent(int item) +{ + int item_pos; + int amt; + + object_type forge; + object_type *q_ptr; + + object_type *o_ptr; + + char o_name[MAX_NLEN]; + + /* 持ち物を取得 */ + o_ptr = &inventory[item]; + + /* Assume one item */ + amt = o_ptr->number; + + /* Get local object */ + q_ptr = &forge; + + /* Get a copy of the object */ + object_copy(q_ptr, o_ptr); + + /* Modify quantity */ + q_ptr->number = amt; + + /* + * Hack -- If a rod or wand, allocate total maximum + * timeouts or charges to those being sold. -LM- + */ + if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND)) + { + q_ptr->pval = o_ptr->pval * amt / o_ptr->number; + } + + /* Get a full description */ + object_desc(o_name, q_ptr, 0); + + /* Is there room in the store (or the home?) */ + if (!store_check_num(q_ptr)) + { +#ifdef JP + msg_print("我が家にはもう置く場所がない。"); +#else + msg_print("Your home is full."); +#endif + return; + } + + /* 家に預ける処理 */ + { + /* Describe */ +#ifdef JP + /* msg_format("%sを置いた。(%c)", o_name, index_to_label(item)); */ +#else + /* msg_format("You drop %s (%c).", o_name, index_to_label(item)); */ +#endif + + /* Take it from the players inventory */ + inven_item_increase(item, -amt); + /* inven_item_describe(item); */ + inven_item_optimize(item); + + /* Handle stuff */ + handle_stuff(); + + /* Let the home carry it */ + item_pos = home_carry(q_ptr); + + /* Update store display */ + if (item_pos >= 0) + { + store_top = (item_pos / 12) * 12; + display_inventory(); + } + } +} + +/* アイテム比較 */ +/* アイテムセットを取り出すときに、取り出すべきアイテムかどうかを判定するための関数。 */ +static bool itemset_object_compare(object_type *o_ptr1, object_type *o_ptr2) +{ + /* Item type (from kind) */ + if (o_ptr1->tval != o_ptr2->tval) return FALSE; + /* Item sub-type (from kind) */ + if (o_ptr1->sval != o_ptr2->sval) return FALSE; + + /* チャージ数は変化するため、比較しない */ + /* Item extra-parameter */ + /* if (o_ptr1->pval != o_ptr2->pval) return FALSE; */ + + /* Artifact type, if any */ + if (o_ptr1->name1 != o_ptr2->name1) return FALSE; + /* Ego-Item type, if any */ + if (o_ptr1->name2 != o_ptr2->name2) return FALSE; + + /* なんかよくわからないので、比較しないことにしておこう */ + /* Extra info */ + /* if (o_ptr1->xtra1 != o_ptr2->xtra1) return FALSE; */ + /* if (o_ptr1->xtra2 != o_ptr2->xtra2) return FALSE; */ + /* if (o_ptr1->xtra3 != o_ptr2->xtra3) return FALSE; */ + /* if (o_ptr1->xtra4 != o_ptr2->xtra4) return FALSE; */ + /* if (o_ptr1->xtra5 != o_ptr2->xtra5) return FALSE; */ + + /* サブ装備を持ち出す場合、酸や劣化で変わりうるため比較しない */ + /* Plusses to hit */ + /* if (o_ptr1->to_h != o_ptr2->to_h) return FALSE; */ + /* Plusses to damage */ + /* if (o_ptr1->to_d != o_ptr2->to_d) return FALSE; */ + /* Plusses to AC */ + /* if (o_ptr1->to_a != o_ptr2->to_a) return FALSE; */ + + /* Normal AC */ + if (o_ptr1->ac != o_ptr2->ac) return FALSE; + /* Damage dice/sides */ + if (o_ptr1->dd != o_ptr2->dd) return FALSE; + if (o_ptr1->ds != o_ptr2->ds) return FALSE; + + /* 銘は比較しない */ + /* Inscription index */ + /* if (o_ptr1->inscription && o_ptr2->inscription) { */ + /* cptr insc1 = quark_str(o_ptr1->inscription); */ + /* cptr insc2 = quark_str(o_ptr2->inscription); */ + /* if (strcmp(insc1, insc2) != 0) return FALSE; */ + /* } */ + + /* Artifact name (random artifacts) */ + if (o_ptr1->art_name && o_ptr2->art_name) { + cptr art1 = quark_str(o_ptr1->art_name); + cptr art2 = quark_str(o_ptr2->art_name); + if (strcmp(art1, art2) != 0) return FALSE; + } + + /* サブ装備を持ち出す場合、呪いで変わりうるため比較しない */ + /* Flags for curse */ + /* if (o_ptr1->curse_flags != o_ptr2->curse_flags) return FALSE; */ + + return TRUE; +} + +/* アイテムセットの取り出し */ +static void itemset_takeoff(char itemset_num, object_type *itemset_ptr, int itemset_len) +{ + bool fail_takeoff = FALSE; + + /* 全アイテムを預ける */ + { + int i; + for (i = 0; i < INVEN_PACK; i++) { + object_type *o_ptr = &inventory[0]; + + /* Skip non-objects */ + if (!o_ptr->k_idx) continue; + + /* 預ける */ + home_sell_silent(0); + } + } + + /* アイテムセットの各アイテムを取り出し */ + { + int itemset_idx; + for (itemset_idx = 0; itemset_idx < itemset_len; itemset_idx++) { + object_type *itemset_o_ptr = &itemset_ptr[itemset_idx]; + int takeoff_item_idx; + + /* 家のアイテムを検索して、取り出すアイテムインデックスを取得 */ + takeoff_item_idx = -1; + { + int i; + for (i = 0; i < st_ptr->stock_num; i++) + { + object_type *store_o_ptr = &st_ptr->stock[i]; + + if (itemset_object_compare(itemset_o_ptr, store_o_ptr) == TRUE) { + takeoff_item_idx = i; + break; + } + } + } + + /* 取り出すアイテムが無い場合、continue */ + if (takeoff_item_idx == -1) { + /* 空アイテム以外を取り出そうとして取り出せなかった場合は、失敗フラグを立てる */ + if ( !(itemset_o_ptr->sval == 0 && itemset_o_ptr->tval == 0) ) { + fail_takeoff = TRUE; + } + continue; + } + + /* 取り出し */ + if (!home_purchase_silent(takeoff_item_idx, itemset_o_ptr->number)) { + /* 失敗フラグを立てて、継続 */ + fail_takeoff = TRUE; + } + } + } + + /* 結果表示 */ + { + char buf[128]; +#ifdef JP + if (fail_takeoff == FALSE) { + sprintf(buf, "アイテムセット[%c]を取り出しました。", itemset_num); + } else { + sprintf(buf, "アイテムセット[%c]の取り出し失敗。一部のアイテムを取り出せませんでした。", itemset_num); + } +#else + if (fail_takeoff == FALSE) { + sprintf(buf, "iemset[%c] take off.", itemset_num); + } else { + sprintf(buf, "fail. iemset[%c] take off.", itemset_num); + } +#endif + msg_print(buf); + } +} + +/* 登録 */ +static void itemset_regist(char itemset_num, char *itemset_path) +{ + /* 書き込み */ + if (!save_itemset(itemset_path)) { +#ifdef JP + prt("登録に失敗しました。",0,0); +#else + prt("fail, regist.",0,0); +#endif + return; + } + + /* 結果表示 */ + { + char buf[128]; +#ifdef JP + sprintf(buf, "アイテムセット[%c]を登録しました。", itemset_num); +#else + sprintf(buf, "itemset[%c] regist.", itemset_num); +#endif + msg_print(buf); + } + +} + +/* アイテムセット処理 */ +static void itemset_main_process(s16b command_cmd) +{ + static object_type *itemset; + static int itemset_len = 0; + static int itemset_init = FALSE; + char itemset_path[1024]; + + /* '5' を正常に読み込むためのhack */ + if (command_cmd == ',') command_cmd = '5'; + + /* 初回のみ、アイテムセット用メモリを初期化。以降使いまわす */ + if (!itemset_init) + { + /* Allocate it */ + C_MAKE(itemset, INVEN_TOTAL, object_type); + itemset_init = TRUE; + } + + /* ファイル名取得 */ + { + int selected_set_num = command_cmd - '0'; + char filename[32]; + + sprintf(filename, "itemset%d.dat", selected_set_num); + path_build(itemset_path, sizeof(itemset_path), ANGBAND_DIR_USER, filename); + } + + /* アイテムセットの読み込み */ + if (!load_itemset(itemset_path, itemset, &itemset_len)) + { +#ifdef JP + msg_print("アイテムセットの読み込みに失敗しました。"); +#else + msg_print("fail, load itemset."); +#endif + return; + } + + /* アイテムセット選択時のプロンプト */ + while (TRUE) + { + char input_key; + int prompt_loop_exit; + prompt_loop_exit = TRUE; + + /* アイテムセット表示 */ + screen_save(); + (void)show_itemset(0, itemset); + + /* プロンプト表示 */ + { + char buf[128]; +#ifdef JP + sprintf(buf, "アイテムセット[%c] (Enter:取り出し, r:登録): ", command_cmd); +#else + sprintf(buf, "itemset[%c] (Enter:Takeoff, r:Regist): ", command_cmd); +#endif + prt(buf,0,0); + } + input_key = inkey(); + prt("",0,0); + + /* Load screen */ + screen_load(); + + /* 入力結果ごとに処理 */ + switch (input_key) { + case 'R': + case 'r': + /* 登録 */ + itemset_regist(command_cmd, itemset_path); + break; + case '\r': + case '\n': + /* 取り出し */ + itemset_takeoff(command_cmd, itemset, itemset_len); + break; + case ESCAPE: + /* 何もせずに抜ける */ + break; + default: + /* その他は、もう一回 */ + prompt_loop_exit = FALSE; + } + + if (prompt_loop_exit == TRUE) break; + } +} Index: src/load.c =================================================================== --- src/load.c (revision 2930) +++ src/load.c (working copy) @@ -4068,3 +4068,109 @@ /* Result */ return ok; } +/* + * アイテムセットのload + * + * rd_savefile_new から、持ち物を読み込む部分のみ抜き出し。 + * ただし、読込先は*itemsetにする。 + */ +bool load_itemset(char *name, object_type *itemset_ptr, int *itemset_len_ptr) +{ + /* アイテムセットのクリア */ + { + int i; + for (i = 0; i < INVEN_TOTAL; i++) + { + object_wipe( &itemset_ptr[i] ); + } + } + + /* Initialize */ + { + /* No encryption */ + xor_byte = 0; + + /* Clear the checksums */ + v_check = 0L; + x_check = 0L; + + /* No file yet */ + fff = NULL; + } + + /* The savefile is a binary file */ + fff = my_fopen(name, "rb"); + + /* Paranoia */ + if (!fff) { + /* ファイルが無い場合、全部空のアイテムセットになる */ + return (TRUE); + } + + /* Read the version number of the savefile */ + { + /* Old savefile will be version 0.0.0.3 */ + rd_byte(&h_ver_extra); + rd_byte(&h_ver_patch); + rd_byte(&h_ver_minor); + rd_byte(&h_ver_major); + } + + /* アイテムセットの読み込み */ + { + object_type forge; + object_type *q_ptr; + int slot = 0; + + /* アイテム数初期化 */ + *itemset_len_ptr = 0; + + /* Read until done */ + while (1) + { + u16b n; + + /* Get the next item index */ + rd_u16b(&n); + + /* Nope, we reached the end */ + if (n == 0xFFFF) break; + + /* Get local object */ + q_ptr = &forge; + + /* Wipe the object */ + object_wipe(q_ptr); + + /* Read the item */ + rd_item(q_ptr); + + /* Hack -- verify item */ + /* 意味わからんけど、(!q_ptr->k_idx)な持ち物は書き込まないハズ */ + if (!q_ptr->k_idx) + { + my_fclose(fff); + return (FALSE); + } + + /* 読み込んだアイテム→アイテムセット */ + { + /* Player touches it */ + q_ptr->marked |= OM_TOUCHED; + + /* Copy object */ + object_copy(&itemset_ptr[slot], q_ptr); + + /* One more item */ + slot++; + } + } + *itemset_len_ptr = slot; + } + + /* Close the file */ + my_fclose(fff); + + /* Result */ + return (TRUE); +} Index: src/save.c =================================================================== --- src/save.c (revision 2930) +++ src/save.c (working copy) @@ -2232,3 +2232,66 @@ /* Return the result */ return ok; } +/* + * アイテムセットのsave + * + * save_player_aux から、持ち物を書き込む部分のみ抜き出し。 + */ +bool save_itemset(char *name) +{ + /* Initialize */ + { + /* No encryption */ + xor_byte = 0; + + /* Reset the checksum */ + v_stamp = 0L; + x_stamp = 0L; + + /* No file yet */ + fff = NULL; + } + + /* Open the savefile */ + fff = my_fopen(name, "wb"); + + /* Successful open */ + if (fff) + { + /* Write the savefile version for Hengband 1.1.1 and later */ + { + wr_byte(H_VER_EXTRA); + wr_byte(H_VER_PATCH); + wr_byte(H_VER_MINOR); + wr_byte(H_VER_MAJOR); + } + + /* アイテムセットの書き込み */ + { + /* バックの中を書き込み */ + int i; + for (i = 0; i < INVEN_PACK; i++) + { + object_type *o_ptr = &inventory[i]; + + /* Skip non-objects */ + if (!o_ptr->k_idx) continue; + + /* Dump index */ + wr_u16b((u16b)i); + + /* Dump object */ + wr_item(o_ptr); + } + + /* Add a sentinel */ + wr_u16b(0xFFFF); + } + + /* Attempt to close it */ + my_fclose(fff); + } + + /* Success */ + return (TRUE); +}