From: Hourier Date: Sun, 22 Mar 2020 12:58:35 +0000 (+0900) Subject: [Refactor] #40233 Somefunctions moved from store.c/h to store-util.c/h and separated... X-Git-Url: http://git.osdn.net/view?p=hengband%2Fhengband.git;a=commitdiff_plain;h=c9f8dea357889e0465fc9cb227ac82578da442fb [Refactor] #40233 Somefunctions moved from store.c/h to store-util.c/h and separated black-market.c/h from store.c --- diff --git a/Hengband_vcs2017/Hengband/Hengband.vcxproj b/Hengband_vcs2017/Hengband/Hengband.vcxproj index 0fad1163c..7b4a4cbb4 100644 --- a/Hengband_vcs2017/Hengband/Hengband.vcxproj +++ b/Hengband_vcs2017/Hengband/Hengband.vcxproj @@ -210,6 +210,7 @@ + @@ -387,6 +388,7 @@ + diff --git a/Hengband_vcs2017/Hengband/Hengband.vcxproj.filters b/Hengband_vcs2017/Hengband/Hengband.vcxproj.filters index d8060c028..f2c60fcdc 100644 --- a/Hengband_vcs2017/Hengband/Hengband.vcxproj.filters +++ b/Hengband_vcs2017/Hengband/Hengband.vcxproj.filters @@ -559,6 +559,9 @@ market + + market + @@ -1100,6 +1103,9 @@ market + + market + diff --git a/src/Makefile.am b/src/Makefile.am index bfd676c00..5ac6412a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,7 @@ hengband_SOURCES = \ market/poker.c market/poker.h market/store-owners.c market/store-owners.h \ market/store-owner-comments.c market/store-owner-comments.h \ market/articles-on-sale.c market/articles-on-sale.h \ + market/black-market.c market/black-market.h \ market/say-comments.c market/say-comments.h \ market/store-util.c market/store-util.h \ market/gold-magnification-table.c market/gold-magnification-table.h \ diff --git a/src/character-dump.c b/src/character-dump.c index af1de2856..2c1b71f44 100644 --- a/src/character-dump.c +++ b/src/character-dump.c @@ -498,38 +498,38 @@ static void dump_aux_equipment_inventory(player_type *creature_ptr, FILE *fff) */ static void dump_aux_home_museum(player_type *creature_ptr, FILE *fff) { - store_type *st_ptr; - st_ptr = &town_info[1].store[STORE_HOME]; + store_type *store_ptr; + store_ptr = &town_info[1].store[STORE_HOME]; GAME_TEXT o_name[MAX_NLEN]; - if (st_ptr->stock_num) + if (store_ptr->stock_num) { fprintf(fff, _(" [我が家のアイテム]\n", " [Home Inventory]\n")); TERM_LEN x = 1; - for (int i = 0; i < st_ptr->stock_num; i++) + for (int i = 0; i < store_ptr->stock_num; i++) { if ((i % 12) == 0) fprintf(fff, _("\n ( %d ページ )\n", "\n ( page %d )\n"), x++); - object_desc(creature_ptr, o_name, &st_ptr->stock[i], 0); + object_desc(creature_ptr, o_name, &store_ptr->stock[i], 0); fprintf(fff, "%c) %s\n", I2A(i % 12), o_name); } fprintf(fff, "\n\n"); } - st_ptr = &town_info[1].store[STORE_MUSEUM]; + store_ptr = &town_info[1].store[STORE_MUSEUM]; - if (st_ptr->stock_num == 0) return; + if (store_ptr->stock_num == 0) return; fprintf(fff, _(" [博物館のアイテム]\n", " [Museum]\n")); TERM_LEN x = 1; - for (int i = 0; i < st_ptr->stock_num; i++) + for (int i = 0; i < store_ptr->stock_num; i++) { #ifdef JP if ((i % 12) == 0) fprintf(fff, "\n ( %d ページ )\n", x++); - object_desc(creature_ptr, o_name, &st_ptr->stock[i], 0); + object_desc(creature_ptr, o_name, &store_ptr->stock[i], 0); fprintf(fff, "%c) %s\n", I2A(i % 12), o_name); #else if ((i % 12) == 0) fprintf(fff, "\n ( page %d )\n", x++); diff --git a/src/cmd/cmd-dump.c b/src/cmd/cmd-dump.c index a88780e7a..51fa85e51 100644 --- a/src/cmd/cmd-dump.c +++ b/src/cmd/cmd-dump.c @@ -641,7 +641,7 @@ static void do_cmd_knowledge_inven(player_type *creature_ptr) { FILE *fff; GAME_TEXT file_name[1024]; - store_type *st_ptr; + store_type *store_ptr; OBJECT_TYPE_VALUE tval; int j = 0; @@ -676,11 +676,11 @@ static void do_cmd_knowledge_inven(player_type *creature_ptr) do_cmd_knowledge_inven_aux(creature_ptr, fff, &creature_ptr->inventory_list[i], &j, tval, where); } - st_ptr = &town_info[1].store[STORE_HOME]; + store_ptr = &town_info[1].store[STORE_HOME]; strcpy(where, _("家", "H ")); - for (int i = 0; i < st_ptr->stock_num; i++) + for (int i = 0; i < store_ptr->stock_num; i++) { - do_cmd_knowledge_inven_aux(creature_ptr, fff, &st_ptr->stock[i], &j, tval, where); + do_cmd_knowledge_inven_aux(creature_ptr, fff, &store_ptr->stock[i], &j, tval, where); } } @@ -3155,10 +3155,10 @@ static void do_cmd_knowledge_home(player_type *player_ptr) return; } - store_type *st_ptr; - st_ptr = &town_info[1].store[STORE_HOME]; + store_type *store_ptr; + store_ptr = &town_info[1].store[STORE_HOME]; - if (st_ptr->stock_num) + if (store_ptr->stock_num) { #ifdef JP TERM_LEN x = 1; @@ -3166,11 +3166,11 @@ static void do_cmd_knowledge_home(player_type *player_ptr) fprintf(fff, _(" [ 我が家のアイテム ]\n", " [Home Inventory]\n")); concptr paren = ")"; GAME_TEXT o_name[MAX_NLEN]; - for (int i = 0; i < st_ptr->stock_num; i++) + for (int i = 0; i < store_ptr->stock_num; i++) { #ifdef JP if ((i % 12) == 0) fprintf(fff, "\n ( %d ページ )\n", x++); - object_desc(player_ptr, o_name, &st_ptr->stock[i], 0); + object_desc(player_ptr, o_name, &store_ptr->stock[i], 0); if (strlen(o_name) <= 80 - 3) { fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name); @@ -3187,7 +3187,7 @@ static void do_cmd_knowledge_home(player_type *player_ptr) fprintf(fff, " %.77s\n", o_name + n); } #else - object_desc(player_ptr, o_name, &st_ptr->stock[i], 0); + object_desc(player_ptr, o_name, &store_ptr->stock[i], 0); fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name); #endif } diff --git a/src/core.c b/src/core.c index 1286dfc56..1f7321f49 100644 --- a/src/core.c +++ b/src/core.c @@ -4629,18 +4629,18 @@ void prevent_turn_overflow(player_type *player_ptr) { for (int j = 0; j < MAX_STORES; j++) { - store_type *st_ptr = &town_info[i].store[j]; + store_type *store_ptr = &town_info[i].store[j]; - if (st_ptr->last_visit > -10L * TURNS_PER_TICK * STORE_TICKS) + if (store_ptr->last_visit > -10L * TURNS_PER_TICK * STORE_TICKS) { - st_ptr->last_visit -= rollback_turns; - if (st_ptr->last_visit < -10L * TURNS_PER_TICK * STORE_TICKS) st_ptr->last_visit = -10L * TURNS_PER_TICK * STORE_TICKS; + store_ptr->last_visit -= rollback_turns; + if (store_ptr->last_visit < -10L * TURNS_PER_TICK * STORE_TICKS) store_ptr->last_visit = -10L * TURNS_PER_TICK * STORE_TICKS; } - if (st_ptr->store_open) + if (store_ptr->store_open) { - st_ptr->store_open -= rollback_turns; - if (st_ptr->store_open < 1) st_ptr->store_open = 1; + store_ptr->store_open -= rollback_turns; + if (store_ptr->store_open < 1) store_ptr->store_open = 1; } } } diff --git a/src/init.c b/src/init.c index 87f930440..0e27a8d4c 100644 --- a/src/init.c +++ b/src/init.c @@ -764,7 +764,7 @@ static errr init_towns(void) for (int j = 0; j < MAX_STORES; j++) { /* Access the store */ - store_type *st_ptr = &town_info[i].store[j]; + store_type *store_ptr = &town_info[i].store[j]; if ((i > 1) && (j == STORE_MUSEUM || j == STORE_HOME)) continue; @@ -776,28 +776,28 @@ static errr init_towns(void) */ if (j == STORE_HOME) { - st_ptr->stock_size = (STORE_INVEN_MAX * 10); + store_ptr->stock_size = (STORE_INVEN_MAX * 10); } else if (j == STORE_MUSEUM) { - st_ptr->stock_size = (STORE_INVEN_MAX * 50); + store_ptr->stock_size = (STORE_INVEN_MAX * 50); } else { - st_ptr->stock_size = STORE_INVEN_MAX; + store_ptr->stock_size = STORE_INVEN_MAX; } /* Allocate the stock */ - C_MAKE(st_ptr->stock, st_ptr->stock_size, object_type); + C_MAKE(store_ptr->stock, store_ptr->stock_size, object_type); /* No table for the black market or home */ if ((j == STORE_BLACK) || (j == STORE_HOME) || (j == STORE_MUSEUM)) continue; /* Assume full table */ - st_ptr->table_size = STORE_CHOICES; + store_ptr->table_size = STORE_CHOICES; /* Allocate the stock */ - C_MAKE(st_ptr->table, st_ptr->table_size, s16b); + C_MAKE(store_ptr->table, store_ptr->table_size, s16b); /* Scan the choices */ for (int k = 0; k < STORE_CHOICES; k++) @@ -821,7 +821,7 @@ static errr init_towns(void) if (k_idx == max_k_idx) continue; /* Add that item index to the table */ - st_ptr->table[st_ptr->table_num++] = k_idx; + store_ptr->table[store_ptr->table_num++] = k_idx; } } } diff --git a/src/load.c b/src/load.c index 08543c231..d15f92e04 100644 --- a/src/load.c +++ b/src/load.c @@ -1281,7 +1281,7 @@ static void rd_lore(MONRACE_IDX r_idx) /*! * @brief 店置きのアイテムオブジェクトを読み込む / Add the item "o_ptr" to the inventory of the "Home" * @param player_ptr プレーヤーへの参照ポインタ - * @param st_ptr 店舗の参照ポインタ + * @param store_ptr 店舗の参照ポインタ * @param o_ptr アイテムオブジェクト参照ポインタ * @return なし * @details @@ -1292,34 +1292,34 @@ static void rd_lore(MONRACE_IDX r_idx) * Also note that it may not correctly "adapt" to "knowledge" bacoming * known, the player may have to pick stuff up and drop it again. */ -static void home_carry(player_type *player_ptr, store_type *st_ptr, object_type *o_ptr) +static void home_carry(player_type *player_ptr, store_type *store_ptr, object_type *o_ptr) { - for (int i = 0; i < st_ptr->stock_num; i++) + for (int i = 0; i < store_ptr->stock_num; i++) { object_type *j_ptr; - j_ptr = &st_ptr->stock[i]; + j_ptr = &store_ptr->stock[i]; if (!object_similar(j_ptr, o_ptr)) continue; object_absorb(j_ptr, o_ptr); return; } - if (st_ptr->stock_num >= STORE_INVEN_MAX * 10) return; + if (store_ptr->stock_num >= STORE_INVEN_MAX * 10) return; s32b value = object_value(o_ptr); int slot; - for (slot = 0; slot < st_ptr->stock_num; slot++) + for (slot = 0; slot < store_ptr->stock_num; slot++) { - if (object_sort_comp(o_ptr, value, &st_ptr->stock[slot])) break; + if (object_sort_comp(o_ptr, value, &store_ptr->stock[slot])) break; } - for (int i = st_ptr->stock_num; i > slot; i--) + for (int i = store_ptr->stock_num; i > slot; i--) { - st_ptr->stock[i] = st_ptr->stock[i - 1]; + store_ptr->stock[i] = store_ptr->stock[i - 1]; } - st_ptr->stock_num++; - st_ptr->stock[slot] = *o_ptr; + store_ptr->stock_num++; + store_ptr->stock[slot] = *o_ptr; chg_virtue(player_ptr, V_SACRIFICE, -1); } @@ -1333,23 +1333,23 @@ static void home_carry(player_type *player_ptr, store_type *st_ptr, object_type */ static errr rd_store(player_type *player_ptr, int town_number, int store_number) { - store_type *st_ptr; + store_type *store_ptr; bool sort = FALSE; if (z_older_than(10, 3, 3) && (store_number == STORE_HOME)) { - st_ptr = &town_info[1].store[store_number]; - if (st_ptr->stock_num) sort = TRUE; + store_ptr = &town_info[1].store[store_number]; + if (store_ptr->stock_num) sort = TRUE; } else { - st_ptr = &town_info[town_number].store[store_number]; + store_ptr = &town_info[town_number].store[store_number]; } byte own; byte tmp8u; s16b num; - rd_s32b(&st_ptr->store_open); - rd_s16b(&st_ptr->insult_cur); + rd_s32b(&store_ptr->store_open); + rd_s16b(&store_ptr->insult_cur); rd_byte(&own); if (z_older_than(11, 0, 4)) { @@ -1361,11 +1361,11 @@ static errr rd_store(player_type *player_ptr, int town_number, int store_number) rd_s16b(&num); } - rd_s16b(&st_ptr->good_buy); - rd_s16b(&st_ptr->bad_buy); + rd_s16b(&store_ptr->good_buy); + rd_s16b(&store_ptr->bad_buy); - rd_s32b(&st_ptr->last_visit); - st_ptr->owner = own; + rd_s32b(&store_ptr->last_visit); + store_ptr->owner = own; for (int j = 0; j < num; j++) { @@ -1376,17 +1376,17 @@ static errr rd_store(player_type *player_ptr, int town_number, int store_number) rd_item(q_ptr); - bool is_valid_item = st_ptr->stock_num < (store_number == STORE_HOME ? STORE_INVEN_MAX * 10 : store_number == STORE_MUSEUM ? STORE_INVEN_MAX * 50 : STORE_INVEN_MAX); + bool is_valid_item = store_ptr->stock_num < (store_number == STORE_HOME ? STORE_INVEN_MAX * 10 : store_number == STORE_MUSEUM ? STORE_INVEN_MAX * 50 : STORE_INVEN_MAX); if (!is_valid_item) continue; if (sort) { - home_carry(player_ptr, st_ptr, q_ptr); + home_carry(player_ptr, store_ptr, q_ptr); } else { - int k = st_ptr->stock_num++; - object_copy(&st_ptr->stock[k], q_ptr); + int k = store_ptr->stock_num++; + object_copy(&store_ptr->stock[k], q_ptr); } } diff --git a/src/market/black-market.c b/src/market/black-market.c new file mode 100644 index 000000000..9eaa76bad --- /dev/null +++ b/src/market/black-market.c @@ -0,0 +1,41 @@ +#include "angband.h" +#include "floor-town.h" +#include "object-hook.h" +#include "market/black-market.h" +#include "market/store-owners.h" +#include "market/store-util.h" + +/*! + * @brief ブラックマーケット用の無価値品の排除判定 / + * This function will keep 'crap' out of the black market. + * @param player_ptr プレーヤーへの参照ポインタ + * @param o_ptr 判定したいオブジェクトの構造体参照ポインタ + * @return ブラックマーケットにとって無価値な品ならばTRUEを返す + * @details + *
+ * Crap is defined as any item that is "available" elsewhere
+ * Based on a suggestion by "Lee Vogt" 
+ * 
+ */ +bool black_market_crap(player_type *player_ptr, object_type *o_ptr) +{ + if (object_is_ego(o_ptr)) return FALSE; + + if (o_ptr->to_a > 0) return FALSE; + if (o_ptr->to_h > 0) return FALSE; + if (o_ptr->to_d > 0) return FALSE; + + for (int i = 0; i < MAX_STORES; i++) + { + if (i == STORE_HOME) continue; + if (i == STORE_MUSEUM) continue; + + for (int j = 0; j < town_info[player_ptr->town_num].store[i].stock_num; j++) + { + object_type *j_ptr = &town_info[player_ptr->town_num].store[i].stock[j]; + if (o_ptr->k_idx == j_ptr->k_idx) return TRUE; + } + } + + return FALSE; +} diff --git a/src/market/black-market.h b/src/market/black-market.h new file mode 100644 index 000000000..fc0a91852 --- /dev/null +++ b/src/market/black-market.h @@ -0,0 +1,3 @@ +#pragma once + +bool black_market_crap(player_type *player_ptr, object_type *o_ptr); diff --git a/src/market/say-comments.c b/src/market/say-comments.c index e7047b49b..596aae74f 100644 --- a/src/market/say-comments.c +++ b/src/market/say-comments.c @@ -6,7 +6,6 @@ #include "rumor.h" #define RUMOR_CHANCE 8 -int cur_store_num = 0; /*! * @brief 取引成功時の店主のメッセージ処理 / diff --git a/src/market/say-comments.h b/src/market/say-comments.h index cb72e17f5..2de542d60 100644 --- a/src/market/say-comments.h +++ b/src/market/say-comments.h @@ -1,7 +1,5 @@ #pragma once -extern int cur_store_num; - void say_comment_1(player_type *player_ptr); void say_comment_2(PRICE value, int annoyed); void say_comment_3(PRICE value, int annoyed); diff --git a/src/market/store-util.c b/src/market/store-util.c index 6a2fa41d4..34367311e 100644 --- a/src/market/store-util.c +++ b/src/market/store-util.c @@ -1,5 +1,645 @@ -#include "market/store-util.h" +#include "angband.h" +#include "market/store-util.h" +#include "object-hook.h" +#include "objectkind.h" + +int cur_store_num = 0; +store_type *st_ptr = NULL; + +/*! + * @brief 店舗のオブジェクト数を増やす / + * Add the item "o_ptr" to a real stores inventory. + * @param item 増やしたいアイテムのID + * @param num 増やしたい数 + * @return なし + * @details + *
+ * Increase, by a given amount, the number of a certain item
+ * in a certain store.	This can result in zero items.
+ * 
+ * @todo numは本来ITEM_NUMBER型にしたい。 + */ +void store_item_increase(INVENTORY_IDX item, int num) +{ + object_type *o_ptr; + o_ptr = &st_ptr->stock[item]; + int cnt = o_ptr->number + num; + if (cnt > 255) cnt = 255; + else if (cnt < 0) cnt = 0; + + num = cnt - o_ptr->number; + o_ptr->number += (ITEM_NUMBER)num; +} + + +/*! + * @brief 店舗のオブジェクト数を削除する / + * Remove a slot if it is empty + * @param item 削除したいアイテムのID + * @return なし + */ +void store_item_optimize(INVENTORY_IDX item) +{ + object_type *o_ptr; + o_ptr = &st_ptr->stock[item]; + if (!o_ptr->k_idx) return; + if (o_ptr->number) return; + + st_ptr->stock_num--; + for (int j = item; j < st_ptr->stock_num; j++) + { + st_ptr->stock[j] = st_ptr->stock[j + 1]; + } + + object_wipe(&st_ptr->stock[st_ptr->stock_num]); +} + + +/*! + * @brief 店舗の品揃え変化のためにアイテムを削除する / + * Attempt to delete (some of) a random item from the store + * @return なし + * @details + *
+ * Hack -- we attempt to "maintain" piles of items when possible.
+ * 
+ */ +void store_delete(void) +{ + INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num); + int num = st_ptr->stock[what].number; + if (randint0(100) < 50) num = (num + 1) / 2; + if (randint0(100) < 50) num = 1; + if ((st_ptr->stock[what].tval == TV_ROD) || (st_ptr->stock[what].tval == TV_WAND)) + { + st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number; + } + + store_item_increase(what, -num); + store_item_optimize(what); +} + + +/*! + * @brief 安価な消耗品の販売数を増やし、低確率で割引にする / + * Certain "cheap" objects should be created in "piles" + * @param o_ptr 店舗に並べるオブジェクト構造体の参照ポインタ + * @return なし + * @details + *
+ * Some objects can be sold at a "discount" (in small piles)
+ * 
+ */ +static void mass_produce(object_type *o_ptr) +{ + int size = 1; + PRICE cost = object_value(o_ptr); + switch (o_ptr->tval) + { + case TV_FOOD: + case TV_FLASK: + case TV_LITE: + { + if (cost <= 5L) size += damroll(3, 5); + if (cost <= 20L) size += damroll(3, 5); + if (cost <= 50L) size += damroll(2, 2); + break; + } + case TV_POTION: + case TV_SCROLL: + { + if (cost <= 60L) size += damroll(3, 5); + if (cost <= 240L) size += damroll(1, 5); + if (o_ptr->sval == SV_SCROLL_STAR_IDENTIFY) size += damroll(3, 5); + if (o_ptr->sval == SV_SCROLL_STAR_REMOVE_CURSE) size += damroll(1, 4); + break; + } + case TV_LIFE_BOOK: + case TV_SORCERY_BOOK: + case TV_NATURE_BOOK: + case TV_CHAOS_BOOK: + case TV_DEATH_BOOK: + case TV_TRUMP_BOOK: + case TV_ARCANE_BOOK: + case TV_CRAFT_BOOK: + case TV_DAEMON_BOOK: + case TV_CRUSADE_BOOK: + case TV_MUSIC_BOOK: + case TV_HISSATSU_BOOK: + case TV_HEX_BOOK: + { + if (cost <= 50L) size += damroll(2, 3); + if (cost <= 500L) size += damroll(1, 3); + break; + } + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_SHIELD: + case TV_GLOVES: + case TV_BOOTS: + case TV_CLOAK: + case TV_HELM: + case TV_CROWN: + case TV_SWORD: + case TV_POLEARM: + case TV_HAFTED: + case TV_DIGGING: + case TV_BOW: + { + if (object_is_artifact(o_ptr)) break; + if (object_is_ego(o_ptr)) break; + if (cost <= 10L) size += damroll(3, 5); + if (cost <= 100L) size += damroll(3, 5); + break; + } + case TV_SPIKE: + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + { + if (cost <= 5L) size += damroll(5, 5); + if (cost <= 50L) size += damroll(5, 5); + if (cost <= 500L) size += damroll(5, 5); + break; + } + case TV_FIGURINE: + { + if (cost <= 100L) size += damroll(2, 2); + if (cost <= 1000L) size += damroll(2, 2); + break; + } + case TV_CAPTURE: + case TV_STATUE: + case TV_CARD: + { + size = 1; + break; + } + + /* + * Because many rods (and a few wands and staffs) are useful mainly + * in quantity, the Black Market will occasionally have a bunch of + * one kind. -LM- + */ + case TV_ROD: + case TV_WAND: + case TV_STAFF: + { + if ((cur_store_num == STORE_BLACK) && one_in_(3)) + { + if (cost < 1601L) size += damroll(1, 5); + else if (cost < 3201L) size += damroll(1, 3); + } + break; + } + } + + DISCOUNT_RATE discount = 0; + if (cost < 5) + { + discount = 0; + } + else if (one_in_(25)) + { + discount = 25; + } + else if (one_in_(150)) + { + discount = 50; + } + else if (one_in_(300)) + { + discount = 75; + } + else if (one_in_(500)) + { + discount = 90; + } + + if (o_ptr->art_name) + { + discount = 0; + } + + o_ptr->discount = discount; + o_ptr->number = size - (size * discount / 100); + if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND)) + { + o_ptr->pval *= (PARAMETER_VALUE)o_ptr->number; + } +} + + +/*! + * @brief 店舗の品揃え変化のためにアイテムを追加する / + * Creates a random item and gives it to a store + * @param player_ptr プレーヤーへの参照ポインタ + * @return なし + * @details + *
+ * This algorithm needs to be rethought.  A lot.
+ * Currently, "normal" stores use a pre-built array.
+ * Note -- the "level" given to "obj_get_num()" is a "favored"
+ * level, that is, there is a much higher chance of getting
+ * items with a level approaching that of the given level...
+ * Should we check for "permission" to have the given item?
+ * 
+ */ +void store_create(player_type *player_ptr, bool (*black_market_crap)(player_type*, object_type*)) +{ + if (st_ptr->stock_num >= st_ptr->stock_size) return; + + for (int tries = 0; tries < 4; tries++) + { + OBJECT_IDX i; + DEPTH level; + if (cur_store_num == STORE_BLACK) + { + /* Pick a level for object/magic */ + level = 25 + randint0(25); + + /* Random item (usually of given level) */ + i = get_obj_num(player_ptr, level, 0x00000000); + + /* Handle failure */ + if (i == 0) continue; + } + else + { + i = st_ptr->table[randint0(st_ptr->table_num)]; + level = rand_range(1, STORE_OBJ_LEVEL); + } + + object_type forge; + object_type *q_ptr; + q_ptr = &forge; + object_prep(q_ptr, i); + apply_magic(player_ptr, q_ptr, level, AM_NO_FIXED_ART); + if (!store_will_buy(q_ptr)) continue; + + if (q_ptr->tval == TV_LITE) + { + if (q_ptr->sval == SV_LITE_TORCH) q_ptr->xtra4 = FUEL_TORCH / 2; + if (q_ptr->sval == SV_LITE_LANTERN) q_ptr->xtra4 = FUEL_LAMP / 2; + } + + object_known(q_ptr); + q_ptr->ident |= IDENT_STORE; + if (q_ptr->tval == TV_CHEST) continue; + + if (cur_store_num == STORE_BLACK) + { + if (black_market_crap(player_ptr, q_ptr)) continue; + if (object_value(q_ptr) < 10) continue; + } + else + { + if (object_value(q_ptr) <= 0) continue; + } + + mass_produce(q_ptr); + (void)store_carry(q_ptr); + break; + } +} + + +/*! + * @brief オブジェクトが祝福されているかの判定を返す / + * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ + * @return アイテムが祝福されたアイテムならばTRUEを返す + */ +static bool is_blessed_item(object_type *o_ptr) +{ + BIT_FLAGS flgs[TR_FLAG_SIZE]; + object_flags(o_ptr, flgs); + if (have_flag(flgs, TR_BLESSED)) return TRUE; + else return FALSE; +} + + +/*! + * @brief オブジェクトが所定の店舗で引き取れるかどうかを返す / + * Determine if the current store will purchase the given item + * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ + * @return アイテムが買い取れるならばTRUEを返す + * @note + * Note that a shop-keeper must refuse to buy "worthless" items + */ +bool store_will_buy(object_type *o_ptr) +{ + if ((cur_store_num == STORE_HOME) || (cur_store_num == STORE_MUSEUM)) return TRUE; + switch (cur_store_num) + { + case STORE_GENERAL: + { + switch (o_ptr->tval) + { + case TV_POTION: + if (o_ptr->sval != SV_POTION_WATER) return FALSE; + + case TV_WHISTLE: + case TV_FOOD: + case TV_LITE: + case TV_FLASK: + case TV_SPIKE: + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + case TV_DIGGING: + case TV_CLOAK: + case TV_BOTTLE: + case TV_FIGURINE: + case TV_STATUE: + case TV_CAPTURE: + case TV_CARD: + break; + default: + return FALSE; + } + + break; + } + case STORE_ARMOURY: + { + switch (o_ptr->tval) + { + case TV_BOOTS: + case TV_GLOVES: + case TV_CROWN: + case TV_HELM: + case TV_SHIELD: + case TV_CLOAK: + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_DRAG_ARMOR: + break; + default: + return FALSE; + } + + break; + } + case STORE_WEAPON: + { + switch (o_ptr->tval) + { + case TV_SHOT: + case TV_BOLT: + case TV_ARROW: + case TV_BOW: + case TV_DIGGING: + case TV_POLEARM: + case TV_SWORD: + case TV_HISSATSU_BOOK: + break; + case TV_HAFTED: + { + if (o_ptr->sval == SV_WIZSTAFF) return FALSE; + } + break; + default: + return FALSE; + } + + break; + } + case STORE_TEMPLE: + { + switch (o_ptr->tval) + { + case TV_LIFE_BOOK: + case TV_CRUSADE_BOOK: + case TV_SCROLL: + case TV_POTION: + case TV_HAFTED: + { + break; + } + case TV_FIGURINE: + case TV_STATUE: + { + monster_race *r_ptr = &r_info[o_ptr->pval]; + if (!(r_ptr->flags3 & RF3_EVIL)) + { + if (r_ptr->flags3 & RF3_GOOD) break; + if (r_ptr->flags3 & RF3_ANIMAL) break; + if (my_strchr("?!", r_ptr->d_char)) break; + } + } + case TV_POLEARM: + case TV_SWORD: + { + if (is_blessed_item(o_ptr)) break; + } + default: + return FALSE; + } + + break; + } + case STORE_ALCHEMIST: + { + switch (o_ptr->tval) + { + case TV_SCROLL: + case TV_POTION: + break; + default: + return FALSE; + } + + break; + } + case STORE_MAGIC: + { + switch (o_ptr->tval) + { + case TV_SORCERY_BOOK: + case TV_NATURE_BOOK: + case TV_CHAOS_BOOK: + case TV_DEATH_BOOK: + case TV_TRUMP_BOOK: + case TV_ARCANE_BOOK: + case TV_CRAFT_BOOK: + case TV_DAEMON_BOOK: + case TV_MUSIC_BOOK: + case TV_HEX_BOOK: + case TV_AMULET: + case TV_RING: + case TV_STAFF: + case TV_WAND: + case TV_ROD: + case TV_SCROLL: + case TV_POTION: + case TV_FIGURINE: + break; + case TV_HAFTED: + { + if (o_ptr->sval == SV_WIZSTAFF) break; + else return FALSE; + } + default: + return FALSE; + } + + break; + } + case STORE_BOOK: + { + switch (o_ptr->tval) + { + case TV_SORCERY_BOOK: + case TV_NATURE_BOOK: + case TV_CHAOS_BOOK: + case TV_DEATH_BOOK: + case TV_LIFE_BOOK: + case TV_TRUMP_BOOK: + case TV_ARCANE_BOOK: + case TV_CRAFT_BOOK: + case TV_DAEMON_BOOK: + case TV_CRUSADE_BOOK: + case TV_MUSIC_BOOK: + case TV_HEX_BOOK: + break; + default: + return FALSE; + } + + break; + } + } + + if (object_value(o_ptr) <= 0) return FALSE; + return TRUE; +} + /*! - * todo store.c のユーティリティ関数に相応しいものをここに置く + * @brief 店舗に並べた品を同一品であるかどうか判定する / + * Determine if a store item can "absorb" another item + * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1 + * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2 + * @return 同一扱いできるならTRUEを返す + * @details + *
+ * See "object_similar()" for the same function for the "player"
+ * 
*/ +bool store_object_similar(object_type *o_ptr, object_type *j_ptr) +{ + if (o_ptr == j_ptr) return 0; + if (o_ptr->k_idx != j_ptr->k_idx) return 0; + if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND) && (o_ptr->tval != TV_ROD)) return 0; + if (o_ptr->to_h != j_ptr->to_h) return 0; + if (o_ptr->to_d != j_ptr->to_d) return 0; + if (o_ptr->to_a != j_ptr->to_a) return 0; + if (o_ptr->name2 != j_ptr->name2) return 0; + if (object_is_artifact(o_ptr) || object_is_artifact(j_ptr)) return 0; + for (int i = 0; i < TR_FLAG_SIZE; i++) + if (o_ptr->art_flags[i] != j_ptr->art_flags[i]) return 0; + if (o_ptr->xtra1 || j_ptr->xtra1) return 0; + if (o_ptr->timeout || j_ptr->timeout) return 0; + if (o_ptr->ac != j_ptr->ac) return 0; + if (o_ptr->dd != j_ptr->dd) return 0; + if (o_ptr->ds != j_ptr->ds) return 0; + if (o_ptr->tval == TV_CHEST) return 0; + if (o_ptr->tval == TV_STATUE) return 0; + if (o_ptr->tval == TV_CAPTURE) return 0; + if (o_ptr->discount != j_ptr->discount) return 0; + return TRUE; +} + + +/*! + * @brief 店舗に並べた品を重ね合わせできるかどうか判定する / + * Allow a store item to absorb another item + * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1 + * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2 + * @return 重ね合わせできるならTRUEを返す + * @details + *
+ * See "object_similar()" for the same function for the "player"
+ * 
+ */ +static void store_object_absorb(object_type *o_ptr, object_type *j_ptr) +{ + int max_num = (o_ptr->tval == TV_ROD) ? + MIN(99, MAX_SHORT / k_info[o_ptr->k_idx].pval) : 99; + int total = o_ptr->number + j_ptr->number; + int diff = (total > max_num) ? total - max_num : 0; + o_ptr->number = (total > max_num) ? max_num : total; + if (o_ptr->tval == TV_ROD) + { + o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number; + } + + if (o_ptr->tval == TV_WAND) + { + o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number; + } +} + + +/*! + * @brief 店舗にオブジェクトを加える / + * Add the item "o_ptr" to a real stores inventory. + * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ + * @return 収めた先のID + * @details + *
+ * In all cases, return the slot (or -1) where the object was placed
+ * Note that this is a hacked up version of "inven_carry()".
+ * Also note that it may not correctly "adapt" to "knowledge" bacoming
+ * known, the player may have to pick stuff up and drop it again.
+ * 
+ */ +int store_carry(object_type *o_ptr) +{ + PRICE value = object_value(o_ptr); + if (value <= 0) return -1; + o_ptr->ident |= IDENT_FULL_KNOWN; + o_ptr->inscription = 0; + o_ptr->feeling = FEEL_NONE; + int slot; + for (slot = 0; slot < st_ptr->stock_num; slot++) + { + object_type *j_ptr; + j_ptr = &st_ptr->stock[slot]; + if (store_object_similar(j_ptr, o_ptr)) + { + store_object_absorb(j_ptr, o_ptr); + return slot; + } + } + + if (st_ptr->stock_num >= st_ptr->stock_size) return -1; + + for (slot = 0; slot < st_ptr->stock_num; slot++) + { + object_type *j_ptr; + j_ptr = &st_ptr->stock[slot]; + if (o_ptr->tval > j_ptr->tval) break; + if (o_ptr->tval < j_ptr->tval) continue; + if (o_ptr->sval < j_ptr->sval) break; + if (o_ptr->sval > j_ptr->sval) continue; + if (o_ptr->tval == TV_ROD) + { + if (o_ptr->pval < j_ptr->pval) break; + if (o_ptr->pval > j_ptr->pval) continue; + } + + PRICE j_value = object_value(j_ptr); + if (value > j_value) break; + if (value < j_value) continue; + } + + for (int i = st_ptr->stock_num; i > slot; i--) + { + st_ptr->stock[i] = st_ptr->stock[i - 1]; + } + + st_ptr->stock_num++; + st_ptr->stock[slot] = *o_ptr; + return slot; +} diff --git a/src/market/store-util.h b/src/market/store-util.h index 23eb5f593..83fd60b22 100644 --- a/src/market/store-util.h +++ b/src/market/store-util.h @@ -1,5 +1,7 @@ #pragma once +#define STORE_OBJ_LEVEL 5 /* Magic Level for normal stores */ + #define STORE_GENERAL 0 /*!< 店舗の種類: 雑貨屋 */ #define STORE_ARMOURY 1 /*!< 店舗の種類: 防具屋 */ #define STORE_WEAPON 2 /*!< 店舗の種類: 武器屋 */ @@ -10,3 +12,45 @@ #define STORE_HOME 7 /*!< 店舗の種類: 我が家 */ #define STORE_BOOK 8 /*!< 店舗の種類: 書店 */ #define STORE_MUSEUM 9 /*!< 店舗の種類: 博物館 */ + +/* + * A store, with an owner, various state flags, a current stock + * of items, and a table of items that are often purchased. + */ +typedef struct store_type store_type; + +struct store_type +{ + byte type; /* Store type */ + + byte owner; /* Owner index */ + byte extra; /* Unused for now */ + + s16b insult_cur; /* Insult counter */ + + s16b good_buy; /* Number of "good" buys */ + s16b bad_buy; /* Number of "bad" buys */ + + s32b store_open; /* Closed until this turn */ + + s32b last_visit; /* Last visited on this turn */ + + s16b table_num; /* Table -- Number of entries */ + s16b table_size; /* Table -- Total Size of Array */ + s16b *table; /* Table -- Legal item kinds */ + + s16b stock_num; /* Stock -- Number of entries */ + s16b stock_size; /* Stock -- Total Size of Array */ + object_type *stock; /* Stock -- Actual stock items */ +}; + +extern int cur_store_num; +extern store_type *st_ptr; + +void store_delete(void); +void store_create(player_type *player_ptr, bool(*black_market_crap)(player_type*, object_type*)); +void store_item_increase(INVENTORY_IDX item, int num); +void store_item_optimize(INVENTORY_IDX item); +bool store_will_buy(object_type *o_ptr); +int store_carry(object_type *o_ptr); +bool store_object_similar(object_type *o_ptr, object_type *j_ptr); diff --git a/src/player/process-death.c b/src/player/process-death.c index fbc2e69ac..c33521e7c 100644 --- a/src/player/process-death.c +++ b/src/player/process-death.c @@ -285,13 +285,13 @@ static void inventory_aware(player_type *creature_ptr) static void home_aware(player_type *creature_ptr) { object_type *o_ptr; - store_type *st_ptr; + store_type *store_ptr; for (int i = 1; i < max_towns; i++) { - st_ptr = &town_info[i].store[STORE_HOME]; - for (int j = 0; j < st_ptr->stock_num; j++) + store_ptr = &town_info[i].store[STORE_HOME]; + for (int j = 0; j < store_ptr->stock_num; j++) { - o_ptr = &st_ptr->stock[j]; + o_ptr = &store_ptr->stock[j]; if (!o_ptr->k_idx) continue; object_aware(creature_ptr, o_ptr); @@ -338,19 +338,19 @@ static void show_dead_home_items(player_type *creature_ptr) { for (int l = 1; l < max_towns; l++) { - store_type *st_ptr; - st_ptr = &town_info[l].store[STORE_HOME]; - if (st_ptr->stock_num == 0) continue; + store_type *store_ptr; + store_ptr = &town_info[l].store[STORE_HOME]; + if (store_ptr->stock_num == 0) continue; - for (int i = 0, k = 0; i < st_ptr->stock_num; k++) + for (int i = 0, k = 0; i < store_ptr->stock_num; k++) { Term_clear(); - for (int j = 0; (j < 12) && (i < st_ptr->stock_num); j++, i++) + for (int j = 0; (j < 12) && (i < store_ptr->stock_num); j++, i++) { GAME_TEXT o_name[MAX_NLEN]; char tmp_val[80]; object_type *o_ptr; - o_ptr = &st_ptr->stock[i]; + o_ptr = &store_ptr->stock[i]; sprintf(tmp_val, "%c) ", I2A(j)); prt(tmp_val, j + 2, 4); object_desc(creature_ptr, o_name, o_ptr, 0); diff --git a/src/save.c b/src/save.c index 50d89f7df..ab5cb4393 100644 --- a/src/save.c +++ b/src/save.c @@ -23,6 +23,7 @@ #include "dungeon.h" #include "quest.h" #include "store.h" +#include "market/store-util.h" #include "wild.h" #include "floor.h" #include "floor-events.h" @@ -402,34 +403,34 @@ static void wr_xtra(KIND_OBJECT_IDX k_idx) /*! * @brief セーブデータに店舗情報を書き込む / Write a "store" record - * @param st_ptr 店舗情報の参照ポインタ + * @param store_ptr 店舗情報の参照ポインタ * @return なし */ -static void wr_store(store_type *st_ptr) +static void wr_store(store_type *store_ptr) { /* Save the "open" counter */ - wr_u32b(st_ptr->store_open); + wr_u32b(store_ptr->store_open); /* Save the "insults" */ - wr_s16b(st_ptr->insult_cur); + wr_s16b(store_ptr->insult_cur); /* Save the current owner */ - wr_byte(st_ptr->owner); + wr_byte(store_ptr->owner); /* Save the stock size */ - wr_s16b(st_ptr->stock_num); + wr_s16b(store_ptr->stock_num); /* Save the "haggle" info */ - wr_s16b(st_ptr->good_buy); - wr_s16b(st_ptr->bad_buy); + wr_s16b(store_ptr->good_buy); + wr_s16b(store_ptr->bad_buy); - wr_s32b(st_ptr->last_visit); + wr_s32b(store_ptr->last_visit); /* Save the stock */ - for (int j = 0; j < st_ptr->stock_num; j++) + for (int j = 0; j < store_ptr->stock_num; j++) { /* Save each item in stock */ - wr_item(&st_ptr->stock[j]); + wr_item(&store_ptr->stock[j]); } } diff --git a/src/store.c b/src/store.c index 3ff56e498..952b0026e 100644 --- a/src/store.c +++ b/src/store.c @@ -15,6 +15,8 @@ #include "market/store-owners.h" #include "market/store-util.h" #include "market/gold-magnification-table.h" +#include "market/store-util.h" +#include "market/black-market.h" #include "core.h" #include "util.h" #include "term.h" @@ -61,7 +63,6 @@ static int store_top = 0; static int store_bottom = 0; static int xtra_stock = 0; -static store_type *st_ptr = NULL; static const owner_type *ot_ptr = NULL; static s16b old_town_num = 0; static s16b inner_town_num = 0; @@ -126,222 +127,6 @@ static PRICE price_item(player_type *player_ptr, object_type *o_ptr, int greed, /*! - * @brief 安価な消耗品の販売数を増やし、低確率で割引にする / - * Certain "cheap" objects should be created in "piles" - * @param o_ptr 店舗に並べるオブジェクト構造体の参照ポインタ - * @return なし - * @details - *
- * Some objects can be sold at a "discount" (in small piles)
- * 
- */ -static void mass_produce(object_type *o_ptr) -{ - int size = 1; - PRICE cost = object_value(o_ptr); - switch (o_ptr->tval) - { - case TV_FOOD: - case TV_FLASK: - case TV_LITE: - { - if (cost <= 5L) size += damroll(3, 5); - if (cost <= 20L) size += damroll(3, 5); - if (cost <= 50L) size += damroll(2, 2); - break; - } - case TV_POTION: - case TV_SCROLL: - { - if (cost <= 60L) size += damroll(3, 5); - if (cost <= 240L) size += damroll(1, 5); - if (o_ptr->sval == SV_SCROLL_STAR_IDENTIFY) size += damroll(3, 5); - if (o_ptr->sval == SV_SCROLL_STAR_REMOVE_CURSE) size += damroll(1, 4); - break; - } - case TV_LIFE_BOOK: - case TV_SORCERY_BOOK: - case TV_NATURE_BOOK: - case TV_CHAOS_BOOK: - case TV_DEATH_BOOK: - case TV_TRUMP_BOOK: - case TV_ARCANE_BOOK: - case TV_CRAFT_BOOK: - case TV_DAEMON_BOOK: - case TV_CRUSADE_BOOK: - case TV_MUSIC_BOOK: - case TV_HISSATSU_BOOK: - case TV_HEX_BOOK: - { - if (cost <= 50L) size += damroll(2, 3); - if (cost <= 500L) size += damroll(1, 3); - break; - } - case TV_SOFT_ARMOR: - case TV_HARD_ARMOR: - case TV_SHIELD: - case TV_GLOVES: - case TV_BOOTS: - case TV_CLOAK: - case TV_HELM: - case TV_CROWN: - case TV_SWORD: - case TV_POLEARM: - case TV_HAFTED: - case TV_DIGGING: - case TV_BOW: - { - if (object_is_artifact(o_ptr)) break; - if (object_is_ego(o_ptr)) break; - if (cost <= 10L) size += damroll(3, 5); - if (cost <= 100L) size += damroll(3, 5); - break; - } - case TV_SPIKE: - case TV_SHOT: - case TV_ARROW: - case TV_BOLT: - { - if (cost <= 5L) size += damroll(5, 5); - if (cost <= 50L) size += damroll(5, 5); - if (cost <= 500L) size += damroll(5, 5); - break; - } - case TV_FIGURINE: - { - if (cost <= 100L) size += damroll(2, 2); - if (cost <= 1000L) size += damroll(2, 2); - break; - } - case TV_CAPTURE: - case TV_STATUE: - case TV_CARD: - { - size = 1; - break; - } - - /* - * Because many rods (and a few wands and staffs) are useful mainly - * in quantity, the Black Market will occasionally have a bunch of - * one kind. -LM- - */ - case TV_ROD: - case TV_WAND: - case TV_STAFF: - { - if ((cur_store_num == STORE_BLACK) && one_in_(3)) - { - if (cost < 1601L) size += damroll(1, 5); - else if (cost < 3201L) size += damroll(1, 3); - } - break; - } - } - - DISCOUNT_RATE discount = 0; - if (cost < 5) - { - discount = 0; - } - else if (one_in_(25)) - { - discount = 25; - } - else if (one_in_(150)) - { - discount = 50; - } - else if (one_in_(300)) - { - discount = 75; - } - else if (one_in_(500)) - { - discount = 90; - } - - if (o_ptr->art_name) - { - discount = 0; - } - - o_ptr->discount = discount; - o_ptr->number = size - (size * discount / 100); - if ((o_ptr->tval == TV_ROD) || (o_ptr->tval == TV_WAND)) - { - o_ptr->pval *= (PARAMETER_VALUE)o_ptr->number; - } -} - - -/*! - * @brief 店舗に並べた品を同一品であるかどうか判定する / - * Determine if a store item can "absorb" another item - * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1 - * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2 - * @return 同一扱いできるならTRUEを返す - * @details - *
- * See "object_similar()" for the same function for the "player"
- * 
- */ -static bool store_object_similar(object_type *o_ptr, object_type *j_ptr) -{ - if (o_ptr == j_ptr) return 0; - if (o_ptr->k_idx != j_ptr->k_idx) return 0; - if ((o_ptr->pval != j_ptr->pval) && (o_ptr->tval != TV_WAND) && (o_ptr->tval != TV_ROD)) return 0; - if (o_ptr->to_h != j_ptr->to_h) return 0; - if (o_ptr->to_d != j_ptr->to_d) return 0; - if (o_ptr->to_a != j_ptr->to_a) return 0; - if (o_ptr->name2 != j_ptr->name2) return 0; - if (object_is_artifact(o_ptr) || object_is_artifact(j_ptr)) return 0; - for (int i = 0; i < TR_FLAG_SIZE; i++) - if (o_ptr->art_flags[i] != j_ptr->art_flags[i]) return 0; - if (o_ptr->xtra1 || j_ptr->xtra1) return 0; - if (o_ptr->timeout || j_ptr->timeout) return 0; - if (o_ptr->ac != j_ptr->ac) return 0; - if (o_ptr->dd != j_ptr->dd) return 0; - if (o_ptr->ds != j_ptr->ds) return 0; - if (o_ptr->tval == TV_CHEST) return 0; - if (o_ptr->tval == TV_STATUE) return 0; - if (o_ptr->tval == TV_CAPTURE) return 0; - if (o_ptr->discount != j_ptr->discount) return 0; - return TRUE; -} - - -/*! - * @brief 店舗に並べた品を重ね合わせできるかどうか判定する / - * Allow a store item to absorb another item - * @param o_ptr 判定するオブジェクト構造体の参照ポインタ1 - * @param j_ptr 判定するオブジェクト構造体の参照ポインタ2 - * @return 重ね合わせできるならTRUEを返す - * @details - *
- * See "object_similar()" for the same function for the "player"
- * 
- */ -static void store_object_absorb(object_type *o_ptr, object_type *j_ptr) -{ - int max_num = (o_ptr->tval == TV_ROD) ? - MIN(99, MAX_SHORT / k_info[o_ptr->k_idx].pval) : 99; - int total = o_ptr->number + j_ptr->number; - int diff = (total > max_num) ? total - max_num : 0; - o_ptr->number = (total > max_num) ? max_num : total; - if (o_ptr->tval == TV_ROD) - { - o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number; - } - - if (o_ptr->tval == TV_WAND) - { - o_ptr->pval += j_ptr->pval * (j_ptr->number - diff) / j_ptr->number; - } -} - - -/*! * @brief 店舗に品を置くスペースがあるかどうかの判定を返す / * Check to see if the shop will be carrying too many objects -RAK- * @param o_ptr 店舗に置きたいオブジェクト構造体の参照ポインタ @@ -425,217 +210,6 @@ static int store_check_num(object_type *o_ptr) /*! - * @brief オブジェクトが祝福されているかの判定を返す / - * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ - * @return アイテムが祝福されたアイテムならばTRUEを返す - */ -static bool is_blessed_item(object_type *o_ptr) -{ - BIT_FLAGS flgs[TR_FLAG_SIZE]; - object_flags(o_ptr, flgs); - if (have_flag(flgs, TR_BLESSED)) return TRUE; - else return FALSE; -} - - -/*! - * @brief オブジェクトが所定の店舗で引き取れるかどうかを返す / - * Determine if the current store will purchase the given item - * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ - * @return アイテムが買い取れるならばTRUEを返す - * @note - * Note that a shop-keeper must refuse to buy "worthless" items - */ -static bool store_will_buy(object_type *o_ptr) -{ - if ((cur_store_num == STORE_HOME) || (cur_store_num == STORE_MUSEUM)) return TRUE; - switch (cur_store_num) - { - case STORE_GENERAL: - { - switch (o_ptr->tval) - { - case TV_POTION: - if (o_ptr->sval != SV_POTION_WATER) return FALSE; - - case TV_WHISTLE: - case TV_FOOD: - case TV_LITE: - case TV_FLASK: - case TV_SPIKE: - case TV_SHOT: - case TV_ARROW: - case TV_BOLT: - case TV_DIGGING: - case TV_CLOAK: - case TV_BOTTLE: - case TV_FIGURINE: - case TV_STATUE: - case TV_CAPTURE: - case TV_CARD: - break; - default: - return FALSE; - } - - break; - } - case STORE_ARMOURY: - { - switch (o_ptr->tval) - { - case TV_BOOTS: - case TV_GLOVES: - case TV_CROWN: - case TV_HELM: - case TV_SHIELD: - case TV_CLOAK: - case TV_SOFT_ARMOR: - case TV_HARD_ARMOR: - case TV_DRAG_ARMOR: - break; - default: - return FALSE; - } - - break; - } - case STORE_WEAPON: - { - switch (o_ptr->tval) - { - case TV_SHOT: - case TV_BOLT: - case TV_ARROW: - case TV_BOW: - case TV_DIGGING: - case TV_POLEARM: - case TV_SWORD: - case TV_HISSATSU_BOOK: - break; - case TV_HAFTED: - { - if (o_ptr->sval == SV_WIZSTAFF) return FALSE; - } - break; - default: - return FALSE; - } - - break; - } - case STORE_TEMPLE: - { - switch (o_ptr->tval) - { - case TV_LIFE_BOOK: - case TV_CRUSADE_BOOK: - case TV_SCROLL: - case TV_POTION: - case TV_HAFTED: - { - break; - } - case TV_FIGURINE: - case TV_STATUE: - { - monster_race *r_ptr = &r_info[o_ptr->pval]; - if (!(r_ptr->flags3 & RF3_EVIL)) - { - if (r_ptr->flags3 & RF3_GOOD) break; - if (r_ptr->flags3 & RF3_ANIMAL) break; - if (my_strchr("?!", r_ptr->d_char)) break; - } - } - case TV_POLEARM: - case TV_SWORD: - { - if (is_blessed_item(o_ptr)) break; - } - default: - return FALSE; - } - - break; - } - case STORE_ALCHEMIST: - { - switch (o_ptr->tval) - { - case TV_SCROLL: - case TV_POTION: - break; - default: - return FALSE; - } - - break; - } - case STORE_MAGIC: - { - switch (o_ptr->tval) - { - case TV_SORCERY_BOOK: - case TV_NATURE_BOOK: - case TV_CHAOS_BOOK: - case TV_DEATH_BOOK: - case TV_TRUMP_BOOK: - case TV_ARCANE_BOOK: - case TV_CRAFT_BOOK: - case TV_DAEMON_BOOK: - case TV_MUSIC_BOOK: - case TV_HEX_BOOK: - case TV_AMULET: - case TV_RING: - case TV_STAFF: - case TV_WAND: - case TV_ROD: - case TV_SCROLL: - case TV_POTION: - case TV_FIGURINE: - break; - case TV_HAFTED: - { - if (o_ptr->sval == SV_WIZSTAFF) break; - else return FALSE; - } - default: - return FALSE; - } - - break; - } - case STORE_BOOK: - { - switch (o_ptr->tval) - { - case TV_SORCERY_BOOK: - case TV_NATURE_BOOK: - case TV_CHAOS_BOOK: - case TV_DEATH_BOOK: - case TV_LIFE_BOOK: - case TV_TRUMP_BOOK: - case TV_ARCANE_BOOK: - case TV_CRAFT_BOOK: - case TV_DAEMON_BOOK: - case TV_CRUSADE_BOOK: - case TV_MUSIC_BOOK: - case TV_HEX_BOOK: - break; - default: - return FALSE; - } - - break; - } - } - - if (object_value(o_ptr) <= 0) return FALSE; - return TRUE; -} - - -/*! * @brief 現在の町の指定された店舗のアイテムを整理する / * Combine and reorder items in store. * @param store_num 店舗ID @@ -839,254 +413,6 @@ static int home_carry(player_type *player_ptr, object_type *o_ptr) /*! - * @brief 店舗にオブジェクトを加える / - * Add the item "o_ptr" to a real stores inventory. - * @param o_ptr 加えたいオブジェクトの構造体参照ポインタ - * @return 収めた先のID - * @details - *
- * In all cases, return the slot (or -1) where the object was placed
- * Note that this is a hacked up version of "inven_carry()".
- * Also note that it may not correctly "adapt" to "knowledge" bacoming
- * known, the player may have to pick stuff up and drop it again.
- * 
- */ -static int store_carry(object_type *o_ptr) -{ - PRICE value = object_value(o_ptr); - if (value <= 0) return -1; - o_ptr->ident |= IDENT_FULL_KNOWN; - o_ptr->inscription = 0; - o_ptr->feeling = FEEL_NONE; - int slot; - for (slot = 0; slot < st_ptr->stock_num; slot++) - { - object_type *j_ptr; - j_ptr = &st_ptr->stock[slot]; - if (store_object_similar(j_ptr, o_ptr)) - { - store_object_absorb(j_ptr, o_ptr); - return slot; - } - } - - if (st_ptr->stock_num >= st_ptr->stock_size) return -1; - - for (slot = 0; slot < st_ptr->stock_num; slot++) - { - object_type *j_ptr; - j_ptr = &st_ptr->stock[slot]; - if (o_ptr->tval > j_ptr->tval) break; - if (o_ptr->tval < j_ptr->tval) continue; - if (o_ptr->sval < j_ptr->sval) break; - if (o_ptr->sval > j_ptr->sval) continue; - if (o_ptr->tval == TV_ROD) - { - if (o_ptr->pval < j_ptr->pval) break; - if (o_ptr->pval > j_ptr->pval) continue; - } - - PRICE j_value = object_value(j_ptr); - if (value > j_value) break; - if (value < j_value) continue; - } - - for (int i = st_ptr->stock_num; i > slot; i--) - { - st_ptr->stock[i] = st_ptr->stock[i - 1]; - } - - st_ptr->stock_num++; - st_ptr->stock[slot] = *o_ptr; - return slot; -} - - -/*! - * @brief 店舗のオブジェクト数を増やす / - * Add the item "o_ptr" to a real stores inventory. - * @param item 増やしたいアイテムのID - * @param num 増やしたい数 - * @return なし - * @details - *
- * Increase, by a given amount, the number of a certain item
- * in a certain store.	This can result in zero items.
- * 
- * @todo numは本来ITEM_NUMBER型にしたい。 - */ -static void store_item_increase(INVENTORY_IDX item, int num) -{ - object_type *o_ptr; - o_ptr = &st_ptr->stock[item]; - int cnt = o_ptr->number + num; - if (cnt > 255) cnt = 255; - else if (cnt < 0) cnt = 0; - - num = cnt - o_ptr->number; - o_ptr->number += (ITEM_NUMBER)num; -} - - -/*! - * @brief 店舗のオブジェクト数を削除する / - * Remove a slot if it is empty - * @param item 削除したいアイテムのID - * @return なし - */ -static void store_item_optimize(INVENTORY_IDX item) -{ - object_type *o_ptr; - o_ptr = &st_ptr->stock[item]; - if (!o_ptr->k_idx) return; - if (o_ptr->number) return; - - st_ptr->stock_num--; - for (int j = item; j < st_ptr->stock_num; j++) - { - st_ptr->stock[j] = st_ptr->stock[j + 1]; - } - - object_wipe(&st_ptr->stock[st_ptr->stock_num]); -} - - -/*! - * @brief ブラックマーケット用の無価値品の排除判定 / - * This function will keep 'crap' out of the black market. - * @param player_ptr プレーヤーへの参照ポインタ - * @param o_ptr 判定したいオブジェクトの構造体参照ポインタ - * @return ブラックマーケットにとって無価値な品ならばTRUEを返す - * @details - *
- * Crap is defined as any item that is "available" elsewhere
- * Based on a suggestion by "Lee Vogt" 
- * 
- */ -static bool black_market_crap(player_type *player_ptr, object_type *o_ptr) -{ - if (object_is_ego(o_ptr)) return FALSE; - - if (o_ptr->to_a > 0) return FALSE; - if (o_ptr->to_h > 0) return FALSE; - if (o_ptr->to_d > 0) return FALSE; - - for (int i = 0; i < MAX_STORES; i++) - { - if (i == STORE_HOME) continue; - if (i == STORE_MUSEUM) continue; - - for (int j = 0; j < town_info[player_ptr->town_num].store[i].stock_num; j++) - { - object_type *j_ptr = &town_info[player_ptr->town_num].store[i].stock[j]; - if (o_ptr->k_idx == j_ptr->k_idx) return TRUE; - } - } - - return FALSE; -} - - -/*! - * @brief 店舗の品揃え変化のためにアイテムを削除する / - * Attempt to delete (some of) a random item from the store - * @return なし - * @details - *
- * Hack -- we attempt to "maintain" piles of items when possible.
- * 
- */ -static void store_delete(void) -{ - INVENTORY_IDX what = (INVENTORY_IDX)randint0(st_ptr->stock_num); - int num = st_ptr->stock[what].number; - if (randint0(100) < 50) num = (num + 1) / 2; - if (randint0(100) < 50) num = 1; - if ((st_ptr->stock[what].tval == TV_ROD) || (st_ptr->stock[what].tval == TV_WAND)) - { - st_ptr->stock[what].pval -= num * st_ptr->stock[what].pval / st_ptr->stock[what].number; - } - - store_item_increase(what, -num); - store_item_optimize(what); -} - - -/*! - * @brief 店舗の品揃え変化のためにアイテムを追加する / - * Creates a random item and gives it to a store - * @param player_ptr プレーヤーへの参照ポインタ - * @return なし - * @details - *
- * This algorithm needs to be rethought.  A lot.
- * Currently, "normal" stores use a pre-built array.
- * Note -- the "level" given to "obj_get_num()" is a "favored"
- * level, that is, there is a much higher chance of getting
- * items with a level approaching that of the given level...
- * Should we check for "permission" to have the given item?
- * 
- */ -static void store_create(player_type *player_ptr) -{ - if (st_ptr->stock_num >= st_ptr->stock_size) return; - - for (int tries = 0; tries < 4; tries++) - { - OBJECT_IDX i; - DEPTH level; - if (cur_store_num == STORE_BLACK) - { - /* Pick a level for object/magic */ - level = 25 + randint0(25); - - /* Random item (usually of given level) */ - i = get_obj_num(player_ptr, level, 0x00000000); - - /* Handle failure */ - if (i == 0) continue; - } - else - { - i = st_ptr->table[randint0(st_ptr->table_num)]; - level = rand_range(1, STORE_OBJ_LEVEL); - } - - object_type forge; - object_type *q_ptr; - q_ptr = &forge; - object_prep(q_ptr, i); - apply_magic(player_ptr, q_ptr, level, AM_NO_FIXED_ART); - if (!store_will_buy(q_ptr)) continue; - - if (q_ptr->tval == TV_LITE) - { - if (q_ptr->sval == SV_LITE_TORCH) q_ptr->xtra4 = FUEL_TORCH / 2; - if (q_ptr->sval == SV_LITE_LANTERN) q_ptr->xtra4 = FUEL_LAMP / 2; - } - - object_known(q_ptr); - q_ptr->ident |= IDENT_STORE; - if (q_ptr->tval == TV_CHEST) continue; - - if (cur_store_num == STORE_BLACK) - { - if (black_market_crap(player_ptr, q_ptr)) continue; - if (object_value(q_ptr) < 10) continue; - } - else - { - if (object_value(q_ptr) <= 0) continue; - } - - mass_produce(q_ptr); - (void)store_carry(q_ptr); - break; - } -} - - -/*! * @brief 店舗の割引対象外にするかどうかを判定 / * Eliminate need to bargain if player has haggled well in the past * @param minprice アイテムの最低販売価格 @@ -2988,7 +2314,7 @@ void store_maint(player_type *player_ptr, int town_num, int store_num) if (j < STORE_MIN_KEEP) j = STORE_MIN_KEEP; if (j >= st_ptr->stock_size) j = st_ptr->stock_size - 1; - while (st_ptr->stock_num < j) store_create(player_ptr); + while (st_ptr->stock_num < j) store_create(player_ptr, black_market_crap); } diff --git a/src/store.h b/src/store.h index c47a8ebb3..282f0f2a5 100644 --- a/src/store.h +++ b/src/store.h @@ -3,42 +3,10 @@ #include "angband.h" #include "market/store-owners.h" -/* - * A store, with an owner, various state flags, a current stock - * of items, and a table of items that are often purchased. - */ -typedef struct store_type store_type; - -struct store_type -{ - byte type; /* Store type */ - - byte owner; /* Owner index */ - byte extra; /* Unused for now */ - - s16b insult_cur; /* Insult counter */ - - s16b good_buy; /* Number of "good" buys */ - s16b bad_buy; /* Number of "bad" buys */ - - s32b store_open; /* Closed until this turn */ - - s32b last_visit; /* Last visited on this turn */ - - s16b table_num; /* Table -- Number of entries */ - s16b table_size; /* Table -- Total Size of Array */ - s16b *table; /* Table -- Legal item kinds */ - - s16b stock_num; /* Stock -- Number of entries */ - s16b stock_size; /* Stock -- Total Size of Array */ - object_type *stock; /* Stock -- Actual stock items */ -}; - /* * Store constants */ #define STORE_INVEN_MAX 24 /* Max number of discrete objs in inven */ -#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 */ diff --git a/src/wizard1.c b/src/wizard1.c index b2991dfac..c09acdf8c 100644 --- a/src/wizard1.c +++ b/src/wizard1.c @@ -27,7 +27,6 @@ #include "floor-town.h" #include "files.h" - /* * The spoiler file being created */ @@ -2474,7 +2473,7 @@ void spoil_random_artifact(player_type *creature_ptr, concptr fname) { int i, j; - store_type *st_ptr; + store_type *store_ptr; object_type *q_ptr; char buf[1024]; @@ -2511,18 +2510,18 @@ void spoil_random_artifact(player_type *creature_ptr, concptr fname) } /* random artifacts in home */ - st_ptr = &town_info[1].store[STORE_HOME]; - for (i = 0; i < st_ptr->stock_num; i++) + store_ptr = &town_info[1].store[STORE_HOME]; + for (i = 0; i < store_ptr->stock_num; i++) { - q_ptr = &st_ptr->stock[i]; + q_ptr = &store_ptr->stock[i]; spoil_random_artifact_aux(creature_ptr, q_ptr, j); } /* random artifacts in museum */ - st_ptr = &town_info[1].store[STORE_MUSEUM]; - for (i = 0; i < st_ptr->stock_num; i++) + store_ptr = &town_info[1].store[STORE_MUSEUM]; + for (i = 0; i < store_ptr->stock_num; i++) { - q_ptr = &st_ptr->stock[i]; + q_ptr = &store_ptr->stock[i]; spoil_random_artifact_aux(creature_ptr, q_ptr, j); } }