/************************************************************************** * # # # ## # # ### ## ## ### http://www.lyonesse.it * * # # # # # ## # # # # # * * # # # # # ## ## # # ## ## ## # # ## * * # # # # # ## # # # # # # # # # # # * * ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 * * * * -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir * * * * ********************************************************************** * * * * File: goods.c * * * * Goods code * * Trading Post code * * Market code * * Market Affections code * * * **************************************************************************/ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "handler.h" #include "interpreter.h" #define IS_VALID_GOOD(sn) \ ((sn) >= 0 && (sn) < top_goods \ && goods_table[(sn)] \ && goods_table[(sn)]->name) #define IS_VALID_TYPE(sn) \ ((sn) >= 0 && (sn) < top_good_type \ && good_types[(sn)] \ && good_types[(sn)]->name) #if defined(KEY) #undef KEY #endif #define KEY(literal, field, value) \ if (!str_cmp(word, literal)) \ { \ field = value; \ fMatch = TRUE; \ break; \ } /* external funcs */ SPECIAL(tradingpost); char *get_spell_name(char *argument); int calc_trade_value(int gnum, int mnum); int Season(void); void fwrite_building(BUILDING_DATA *bld); void calc_prod(MARKET_DATA *pMk, GOOD_DATA *pGood, TRP_GOOD *tGood, MARKET_GOOD *pGM); void calc_price(MARKET_DATA *pMk, GOOD_DATA *pGood, MARKET_GOOD *pGM); /* globals */ MARKET_DATA *first_market = NULL; MARKET_DATA *last_market = NULL; TRADING_POST *first_trading_post = NULL; TRADING_POST *last_trading_post = NULL; GOOD_TYPE *good_types[MAX_TYPE_CODE]; GOOD_DATA *goods_table[MAX_GOOD]; MARKET_GOOD *GoodsMarkets[MAX_GOOD][MAX_MARKET]; int top_goods = 0; int top_good_type = 0; int top_tp_vnum = 0; int reset_markets = 0; /* local functions */ MARKET_DATA *find_market(int vnum); void SaveGoodsMarketsTable(bool bTime); void set_mk_aff(int mnum, int nwhat, int bitv, int durat, float value); /* =========================================================================== */ /* Goods Type Code */ /* =========================================================================== */ /* *************************************************************************** */ /* Goods Type finding code */ /* *************************************************************************** */ GOOD_TYPE *get_good_type(int vnum) { int gtn; for (gtn = 0; gtn < top_good_type; gtn++) { if (!IS_VALID_TYPE(gtn)) continue; if (good_types[gtn]->vnum == vnum) break; } if (gtn >= top_good_type) return (NULL); return (good_types[gtn]); } /* *************************************************************************** */ /* Goods Type creation code */ /* *************************************************************************** */ GOOD_TYPE *new_good_type(void) { GOOD_TYPE *gtype; int x; CREATE(gtype, GOOD_TYPE, 1); gtype->name = NULL; gtype->vnum = NOTHING; gtype->elasticity = 1; gtype->cons_speed = 1.00; for (x = 0; x < NUM_SEASONS; x++) gtype->prod_avg[x] = 0; return (gtype); } /* *************************************************************************** */ /* Goods Type load code */ /* *************************************************************************** */ GOOD_TYPE *fread_one_gtype(FILE *fp) { GOOD_TYPE *gtype = new_good_type(); char *word; bool fMatch; for ( ; ; ) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'C': if (!str_cmp(word, "Cons_speed")) { int num = fread_number(fp); float calc = (float)num / 100; gtype->cons_speed = calc; fMatch = TRUE; break; } break; case 'E': KEY("Elast", gtype->elasticity, fread_number(fp)); if (!strcmp(word, "End")) return (gtype); case 'N': KEY("Name", gtype->name, str_dup(fread_word(fp))); break; case 'P': if (!strcmp(word, "Prod")) { int x; for (x = 0; x < NUM_SEASONS; x++) gtype->prod_avg[x] = fread_number(fp); fMatch = TRUE; break; } break; case 'V': KEY("Vnum", gtype->vnum, fread_number(fp)); break; } } return (NULL); } void LoadGoodTypes(void) { FILE *fp; char fname[128]; char letter; char *word; int i; sprintf(fname, "%sgoodtypes.data", LIB_GOODS); if (!(fp = fopen(fname, "r"))) { log("SYSERR: LoadGoodTypes() - cannot open good types file %s.", fname); return; } /* Pre-initialize goods_table with blanks */ for (i = 0; i < MAX_TYPE_CODE; i++) good_types[i] = NULL; top_good_type = 0; for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (feof(fp)) break; if (letter != '#') { log("SYSERR: LoadGoodTypes() - # not found."); break; } word = fread_word(fp); if (!strcmp(word, "TYPE")) { if (top_good_type >= MAX_TYPE_CODE) { log("SYSERR: LoadGoodTypes() - more good types than MAX_TYPE_CODE %d", MAX_TYPE_CODE); fclose(fp); exit(1); } good_types[top_good_type] = fread_one_gtype(fp); top_good_type++; continue; } else if (!strcmp(word, "END")) // Done break; else { log("SYSERR: LoadGoodTypes() - bad section %s", word); continue; } } fclose(fp); } /* =========================================================================== */ /* Goods Code */ /* =========================================================================== */ /* *************************************************************************** */ /* Goods creation code */ /* *************************************************************************** */ GOOD_DATA *new_good(void) { GOOD_DATA *pGood; CREATE(pGood, GOOD_DATA, 1); pGood->name = NULL; pGood->unit = NULL; pGood->short_descr = NULL; pGood->gtype = NULL; pGood->code = 0; pGood->cost = 0; pGood->life = -1; pGood->vnum = 0; pGood->mkvnum = 0; pGood->weight = 0; pGood->docg = 0; return (pGood); } void clear_goods(GOOD_DATA *pGood) { if (pGood->name) STRFREE(pGood->name); if (pGood->unit) STRFREE(pGood->unit); if (pGood->short_descr) STRFREE(pGood->short_descr); pGood->gtype = NULL; } /* *************************************************************************** */ /* Sort Goods Table */ /* *************************************************************************** */ /* Function used by qsort to sort goods */ int goods_comp(GOOD_DATA **g1, GOOD_DATA **g2) { GOOD_DATA *pGood1 = (*g1); GOOD_DATA *pGood2 = (*g2); if (!pGood1 && pGood2) return (1); if (pGood1 && !pGood2) return (-1); if (!pGood1 && !pGood2) return (0); return (str_cmp(pGood1->name, pGood2->name)); } /* * Ordina la tabella delle abilita' con qsort */ void sort_goods_table(void) { log(" Sorting Goods Table."); qsort( &goods_table[0], MAX_GOOD - 1, sizeof(GOOD_DATA *), (int(*)(const void *, const void *)) goods_comp ); } /* *************************************************************************** */ /* Load Goods from file code */ /* *************************************************************************** */ int parse_g_code(char *cname) { if (!str_cmp(cname, "corn")) return (TYPE_CORN); if (!str_cmp(cname, "flour")) return (TYPE_FLOUR); if (!str_cmp(cname, "fabric")) return (TYPE_FABRIC); if (!str_cmp(cname, "hide")) return (TYPE_HIDE); if (!str_cmp(cname, "dye")) return (TYPE_DYE); if (!str_cmp(cname, "metal")) return (TYPE_METAL); if (!str_cmp(cname, "ore")) return (TYPE_ORE); if (!str_cmp(cname, "spice")) return (TYPE_SPICE); if (!str_cmp(cname, "sugar")) return (TYPE_SUGAR); if (!str_cmp(cname, "oil")) return (TYPE_OIL); if (!str_cmp(cname, "wood")) return (TYPE_WOOD); return (NOTHING); } GOOD_DATA *fread_one_good(FILE *fp) { GOOD_DATA *pGood = new_good(); char *word; bool fMatch; for ( ; ; ) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol( fp ); break; case 'C': if (!strcmp(word, "Code")) { //pGood->code = parse_g_code(fread_word(fp)); pGood->code = fread_number(fp); pGood->gtype = get_good_type(pGood->code); fMatch = TRUE; break; } KEY("Cost", pGood->cost, fread_number(fp)); break; case 'E': if (!strcmp(word, "End")) { if (!pGood->gtype) { log("SYSERR: good %d without type.", pGood->vnum); exit(1); return (NULL); } if (!pGood->short_descr || !*pGood->short_descr) { char gname[MAX_STRING_LENGTH]; sprintf(gname, "%s %s", pGood->unit, pGood->name); pGood->short_descr = str_dup(gname); } return (pGood); } break; case 'L': KEY("Life", pGood->life, fread_number(fp)); break; case 'M': KEY("Market", pGood->mkvnum, fread_number(fp)); break; case 'N': KEY("Name", pGood->name, fread_string_nospace(fp)); break; case 'S': KEY("Short_descr", pGood->short_descr, fread_string_nospace(fp)); break; case 'U': KEY("Unit", pGood->unit, str_dup(fread_word(fp))); break; case 'V': KEY("Vnum", pGood->vnum, fread_number(fp)); break; case 'W': KEY("Weight", pGood->weight, fread_number(fp)); break; } if (!fMatch) log("fread_one_good: no match: %s", word); } return (NULL); } void LoadGoods(void) { FILE *fp; char fname[128]; char letter; char *word; int i; sprintf(fname, "%sgoods.data", LIB_GOODS); if (!(fp = fopen(fname, "r"))) { log("SYSERR: LoadGoods() - cannot open goods file %s.", fname); return; } /* Pre-init the goods_table with blank goods */ for (i = 0; i < MAX_GOOD; i++) goods_table[i] = NULL; top_goods = 0; for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (feof(fp)) break; if (letter != '#') { log("SYSERR: LoadGoods() - # not found."); break; } word = fread_word(fp); if (!strcmp(word, "GOODS")) { if (top_goods >= MAX_GOOD) { log("SYSERR: LoadGoods() - more goods than MAX_GOOD %d", MAX_GOOD); fclose(fp); return; } goods_table[top_goods] = fread_one_good(fp); top_goods++; continue; } else if (!strcmp(word, "END")) // Done break; else { log("SYSERR: LoadGoods() - bad section %s", word); continue; } } fclose(fp); } /* *************************************************************************** */ /* Goods finding code */ /* *************************************************************************** */ /* Check for exact matches only */ int bsearch_goods_exact(const char *name, int first, int top) { int sn; for (;;) { sn = (first + top) >> 1; if (!IS_VALID_GOOD(sn)) return (-1); if (!str_cmp(name, goods_table[sn]->name)) return (sn); if (first >= top) return (-1); if (strcmp(name, goods_table[sn]->name) < 1) top = sn - 1; else first = sn + 1; } return (-1); } GOOD_DATA *get_good(int gnum) { int gn; for (gn = 0; gn < top_goods; gn++) { if (!IS_VALID_GOOD(gn)) continue; if (goods_table[gn]->vnum == gnum) break; } if (gn >= top_goods) return (NULL); return (goods_table[gn]); } GOOD_DATA *get_good_by_name(char *gname) { int gn; if ((gn = bsearch_goods_exact(gname, 0, top_goods - 1)) == -1) return (NULL); return (goods_table[gn]); } /* * recursive reverse search for goods object <gnum> */ OBJ_DATA *get_good_object(OBJ_DATA *list, int gnum) { OBJ_DATA *obj = NULL; for (obj = list; obj; obj = obj->prev_content) { if (GET_OBJ_TYPE(obj) == ITEM_GOODS) { if (GET_OBJ_VAL(obj, 0) == gnum) break; } if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER) get_good_object(obj->last_content, gnum); } return (obj); } /* *************************************************************************** */ /* Goods Display Routines */ /* *************************************************************************** */ void list_goods(CHAR_DATA *ch, int mode) { char gbuf[MAX_STRING_LENGTH*2]; int gn; strcpy(gbuf, "List of goods table:\r\n" "-----------------------------------------------\r\n" "Name Unit Cost\r\n" "-----------------------------------------------\r\n" ); for (gn = 0; gn < top_goods; gn++) { if (!IS_VALID_GOOD(gn)) continue; if (mode) { if (goods_table[gn]->cost < mode) continue; } sprintf(gbuf + strlen(gbuf), "%-25s %-10s %4d %5d %5d %5d\r\n", goods_table[gn]->name, goods_table[gn]->unit, goods_table[gn]->cost); } page_string(ch->desc, gbuf, 1); } /* *************************************************************************** */ /* Goods object creation code */ /* *************************************************************************** */ OBJ_DATA *create_good_obj(GOOD_DATA *pGood, int amount) { OBJ_DATA *obj; char buf[MAX_STRING_LENGTH]; if (amount < 0) amount = 1; obj = create_obj(); // setup goods name sprintf(buf, "%s %s", pGood->name, pGood->unit); if (obj->name) free(obj->name); obj->name = str_dup(buf); // setup goods short description sprintf(buf, "%s %s of %s", AN(pGood->unit), pGood->unit, pGood->name); if (obj->short_description) free(obj->short_description); obj->short_description = str_dup(buf); // setup goods description sprintf(buf, "%s %s of %s was placed here.", UAN(pGood->unit), pGood->unit, pGood->name); if (obj->description) free(obj->description); obj->description = str_dup(buf); obj->action_description = NULL; SET_BIT(GET_OBJ_EXTRA(obj), ITEM_UNIQUE); SET_BIT(GET_OBJ_WEAR(obj), ITEM_WEAR_TAKE); GET_OBJ_TYPE(obj) = ITEM_GOODS; GET_OBJ_WEIGHT(obj) = pGood->weight; GET_OBJ_COST(obj) = pGood->cost; GET_OBJ_TIMER(obj) = pGood->life; GET_OBJ_QUALITY(obj) = number(30, 80); obj->count = amount; GET_OBJ_VAL(obj, 0) = pGood->vnum; return (obj); } ACMD(do_newgoods) { OBJ_DATA *obj; GOOD_DATA *pGood; char *g; /* get goods name */ g = get_spell_name(argument); if (g == NULL) { send_to_char("Goods names must be enclosed in the Holy Magic Symbols: '\r\n", ch); return; } argument = strtok(NULL, "\0"); // show the entire list of goods if (!str_cmp(g, "list")) { int mode; if (*argument) { one_argument(argument, arg); if ( !*arg || !is_number(arg) ) mode = 0; else mode = atoi(arg); } else mode = 0; list_goods(ch, mode); return; } if (!(pGood = get_good_by_name(g))) { ch_printf(ch, "There is no goods called '%s'.\r\n", g); return; } obj = create_good_obj(pGood, 1); obj = obj_to_room(obj, ch->in_room); ch_printf(ch, "You create %s %s of %s out of the blue.\r\n", AN(pGood->unit), pGood->unit, pGood->name); sprintf(buf, "$n creates %s %s of %s out of the blue.\r\n", AN(pGood->unit), pGood->unit, pGood->name); act(buf, FALSE, ch, NULL, NULL, TO_ROOM); } /* =========================================================================== */ /* Trading Post Code */ /* =========================================================================== */ /* *************************************************************************** */ /* Trading Post finding code */ /* *************************************************************************** */ TRADING_POST *find_trading_post(int vnum) { TRADING_POST *pTp; if (vnum < 1) return (NULL); for (pTp = first_trading_post; pTp; pTp = pTp->next) { if (pTp->vnum == vnum) break; } return (pTp); } TRP_GOOD *tp_has_goods(TRADING_POST *pTp, int gnum) { TRP_GOOD *tGood; for (tGood = pTp->first_tpgood; tGood; tGood = tGood->next) if (tGood->goods_vnum == gnum) break; return (tGood); } /* *************************************************************************** */ /* Trading Post creation code */ /* *************************************************************************** */ TRADING_POST *new_trading_post(void) { TRADING_POST *pTp; CREATE(pTp, TRADING_POST, 1); pTp->next = NULL; pTp->prev = NULL; pTp->next_in_market = NULL; pTp->market = NULL; pTp->first_tpgood = NULL; pTp->last_tpgood = NULL; pTp->vnum = NOTHING; pTp->type = TP_GCLOSE; // add to the list LINK(pTp, first_trading_post, last_trading_post, next, prev); return (pTp); } /* *************************************************************************** */ /* Load Trading Post from file code */ /* *************************************************************************** */ TRADING_POST *fread_one_tp(FILE *fp) { TRADING_POST *tp = new_trading_post(); char *word; bool fMatch; for ( ; ; ) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol(fp); break; case 'E': if (!strcmp(word, "End")) return (tp); break; case 'G': if (!strcmp(word, "Good")) { TRP_GOOD *tGood; GOOD_DATA *pGood; int vnum; fMatch = TRUE; vnum = fread_number(fp); if (!(pGood = get_good(vnum))) { log("SYSERR: fread_one_tp() - wrong good vnum %d.", vnum); exit(1); } CREATE(tGood, TRP_GOOD, 1); tGood->next = NULL; tGood->prev = NULL; tGood->goods_vnum = vnum; tGood->quantity = fread_number(fp); tGood->prev_qty = fread_number(fp); tGood->stock = fread_number(fp); // add good to tp LINK(tGood, tp->first_tpgood, tp->last_tpgood, next, prev); // assign unassigned goods to the tp market if (tGood->stock && tp->market && !pGood->mkvnum) pGood->mkvnum = tp->market->vnum; // setup GM if needed if (!GoodsMarkets[pGood->vnum][tp->market->vnum]) { log("SYSERR: fread_one_tp() - missing GoodsMarkets data for good %d - market %d.", pGood->vnum, tp->market->vnum); exit(1); // CREATE(GoodsMarkets[pGood->vnum][tp->market->vnum], MARKET_GOOD, 1); } // setup GM.total_tp GoodsMarkets[pGood->vnum][tp->market->vnum]->total_tp++; // increase GM.qty GoodsMarkets[pGood->vnum][tp->market->vnum]->qty += tGood->quantity; break; } break; case 'M': if (!strcmp(word, "Market")) { int mnum = fread_number(fp); fMatch = TRUE; if (mnum == -1) { log("ECONOMY: Trading Post %d without market vnum.", tp->vnum); exit(1); } if (!(tp->market = find_market(mnum))) { log("ECONOMY: Trading Post %d unknown market vnum %d.", tp->vnum, mnum); exit(1); } // increase count of tp tp->market->num_of_tp++; // add to market tp list tp->next_in_market = tp->market->tp_list; tp->market->tp_list = tp; break; } break; case 'T': KEY("Type", tp->type, fread_number(fp)); break; case 'V': KEY("Vnum", tp->vnum, fread_number(fp)); break; } if (!fMatch) log("fread_one_tp: no match: %s", word); } return (NULL); } void LoadTradingPost(void) { FILE *fp; char fname[128]; char letter; char *word; sprintf(fname, "%stradingpost.data", LIB_GOODS); if (!(fp = fopen(fname, "r"))) { log("SYSERR: LoadTradingPost() - cannot open file %s.", fname); return; } top_tp_vnum = 0; for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (feof(fp)) break; if (letter != '#') { log("SYSERR: LoadTradingPost() - # not found."); break; } word = fread_word(fp); if (!strcmp(word, "TRADINGPOST")) { TRADING_POST *pTp; if (!(pTp = fread_one_tp(fp))) { log("SYSERR: LoadTradingPost() - error in reading trading post."); fclose(fp); exit(1); } if (pTp->vnum > top_tp_vnum) top_tp_vnum = pTp->vnum; } else if (!strcmp( word, "END")) // Done break; else { log("SYSERR: LoadTradingPost() - bad section %s", word); continue; } } fclose(fp); if (reset_markets) SaveGoodsMarketsTable(0); } /* *************************************************************************** */ /* Save Trading Post to file code */ /* *************************************************************************** */ void SaveTradingPost(void) { FILE *fp; TRADING_POST *tp; TRP_GOOD *tGood; char fname[128]; if (!first_trading_post) return; sprintf(fname, "%stradingpost.data", LIB_GOODS); if (!(fp = fopen(fname, "w"))) { log("SYSERR: SaveTradingPost() - cannot open file %s.", fname); return; } for (tp = first_trading_post; tp; tp = tp->next) { fprintf(fp, "#TRADINGPOST\n"); fprintf(fp, "Vnum %d\n", tp->vnum); fprintf(fp, "Market %d\n", tp->market ? tp->market->vnum : -1); fprintf(fp, "Type %d\n", tp->type); for (tGood = tp->first_tpgood; tGood; tGood = tGood->next) { if (tGood->quantity <= 0 && tGood->prev_qty <= 0 && !tGood->stock) continue; fprintf(fp, "Good %d %d %d %d\n", tGood->goods_vnum, tGood->quantity, tGood->prev_qty, tGood->stock); } fprintf(fp, "End\n\n"); } fprintf(fp, "#END\n"); fclose(fp); } /* *************************************************************************** */ /* IMMS Command */ /* *************************************************************************** */ const char *tp_type_desc[] = { "closed", "restricted", "limited", "free" }; SHIP_DATA *find_ship( sh_int vnum ); MARKET_DATA *locate_bld_market(BUILDING_DATA *pBld) { MARKET_DATA *pMk = NULL; int iDist = 0; if (!pBld->in_room) return (NULL); if (IS_WILD(pBld->in_room)) { for (pMk = first_market; pMk; pMk = pMk->next) { iDist = (int) distance(GET_X(pBld), GET_Y(pBld), pMk->heart.x, pMk->heart.y); if (iDist <= pMk->size) break; } } else { COORD_DATA coord; coord = zone_table[pBld->in_room->zone].wild.z_start; if (coord.y == 0 && coord.x == 0) { log("SYSERR: cannot retrieve wild position for zone %d.", zone_table[pBld->in_room->zone].number); return (NULL); } for (pMk = first_market; pMk; pMk = pMk->next) { iDist = (int) distance(coord.x, coord.y, pMk->heart.x, pMk->heart.y); if (iDist <= pMk->size) break; } } return (pMk); } ACMD(do_tp) { TRADING_POST *pTp; GOOD_DATA *pGood; char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; char bloc[MAX_STRING_LENGTH]; int tnum, gnum; argument = one_argument(argument, arg); if (!*arg) { send_to_char( "Usage:\r\n" "-----------------------------------------------------------------------\r\n" " command description\r\n" "-----------------------------------------------------------------------\r\n" " tp virtual List of loaded Trading Posts\r\n" " tp list <market vnum> List of Trading Posts in game (1)\r\n" " tp <vnum> Detailed infos\r\n" " tp <vnum> add <good> <stock> Add good to the TP goods list (2)\r\n" " tp <vnum> remove <good> Remove good from the TP goods list\r\n" " tp new <type> Setup a new TP of the given type(3)\r\n" " tp delete <vnum> Destroy given Trading Post\r\n" "-----------------------------------------------------------------------\r\n" " (1) <market vnum> filter TP listing to those of the given market.\r\n" " (2) <stock> can be 0 or 1, depending if the good should be produced in\r\n" " the Trading Post's market. If 0, you can omit the parameter.\r\n" " (3) to create a new Trading Post, you must be in a STORE type building\r\n" "-----------------------------------------------------------------------\r\n" , ch); return; } if (is_abbrev(arg, "virtual")) { char buf[MAX_STRING_LENGTH]; strcpy(buf, "List of loaded Trading Posts.\r\n"); for (pTp = first_trading_post; pTp; pTp = pTp->next) { sprintf(buf+strlen(buf), " Vnum: [%d] Market: [%d] Type: %s\r\n", pTp->vnum, (pTp->market ? pTp->market->vnum : NOWHERE), tp_type_desc[pTp->type]); } page_string(ch->desc, buf, 0); return; } if (is_abbrev(arg, "list")) { MARKET_DATA *pMk = NULL; int mnum; argument = one_argument(argument, arg); if (!*arg || !is_number(arg)) mnum = 0; else { mnum = atoi(arg); if (mnum < 1 || mnum > MAX_MARKET) mnum = 0; else if (!(pMk = find_market(mnum))) mnum = 0; } strcpy(buf, "List of Trading Posts in"); if (mnum) sprintf(buf + strlen(buf), " market [%d] '%s'.\r\n", mnum, pMk->name); else strcat(buf, " game.\r\n"); send_to_char(buf, ch); *buf = '\0'; for (pTp = first_trading_post; pTp; pTp = pTp->next) { if (!pTp->market) continue; if (!pTp->in_room) continue; if (mnum && pTp->market->vnum != mnum) continue; // where is this TP ?? if (IS_BUILDING(pTp->in_room)) sprintf(bloc, "Building [%d]", pTp->in_room->extra_data->vnum); else if (IS_WILD(pTp->in_room)) sprintf(bloc, "Wilderness [%d %d]", GET_Y(pTp), GET_X(pTp)); else if (pTp->in_room->number != NOWHERE) sprintf(bloc, "Room [%d] '%s'", pTp->in_room->number, ROOM_NAME(pTp)); else strcpy(bloc, "NOWHERE"); sprintf(buf+strlen(buf), " [%d] Type: %s Location: %s\r\n", pTp->vnum, tp_type_desc[pTp->type], bloc); } if (!*buf) send_to_char("No Trading Post found.\r\n", ch); else page_string(ch->desc, buf, 0); return; } if (is_abbrev(arg, "new")) { BUILDING_DATA *pBld; int nt; // building checks.... if (!IN_BUILDING(ch)) { send_to_char("You must be in a STORE type building to create a new TP.\r\n", ch); return; } pBld = ch->in_building; if (!pBld || pBld->type->vnum != BLD_STORE) { send_to_char("You must be in a STORE type building to create a new TP.\r\n", ch); return; } if (pBld->trp) { send_to_char("This building already host a Trading Post.\r\n", ch); return; } // TP type checks.... argument = one_argument(argument, arg); if (!*arg) { send_to_char("You must specify a TP type.\r\nPossible types are:\r\n", ch); for (nt = 0; nt < NUM_TP_TYPES; nt++) ch_printf(ch, " - %s\r\n", tp_type_desc[nt]); return; } for (nt = 0; nt < NUM_TP_TYPES; nt++) { if (is_abbrev(arg, tp_type_desc[nt])) break; } if (nt >= NUM_TP_TYPES) { send_to_char("Unknown TP type.\r\nPossible types are:\r\n", ch); for (nt = 0; nt < NUM_TP_TYPES; nt++) ch_printf(ch, " - %s\r\n", tp_type_desc[nt]); return; } // setup the new TP pTp = new_trading_post(); pTp->vnum = ++top_tp_vnum; pTp->type = nt; pTp->in_room = pBld->rooms[ch->in_room->number]; pTp->market = locate_bld_market(pBld); if (pTp->market) { pTp->next_in_market = pTp->market->tp_list; pTp->market->tp_list = pTp; } // assing building tp status pBld->trp = pTp; // assign to current building room the special procedure pBld->rooms[ch->in_room->number]->func = tradingpost; fwrite_building(pBld); SaveTradingPost(); return; } if (!str_cmp(arg, "delete")) { send_to_char("Not yet implemented, sorry.\r\n", ch); return; } if (!is_number(arg)) return; tnum = atoi(arg); if (tnum < 0 || tnum > top_tp_vnum) { ch_printf(ch, "Invalid TP vnum %d.\r\n", tnum); return; } if (!(pTp = find_trading_post(tnum))) { ch_printf(ch, "Cannot find any TP with vnum %d.\r\n", tnum); return; } argument = two_arguments(argument, arg, arg2); // print detailed info about TP if (!*arg) { TRP_GOOD *tGood; GOOD_DATA *pGood; int price; if (pTp->in_room) { // where is this TP ?? if (IS_BUILDING(pTp->in_room)) sprintf(bloc, "Building [%d]", pTp->in_room->extra_data->vnum); else if (IS_WILD(pTp->in_room)) sprintf(bloc, "Wilderness [%d %d]", GET_Y(pTp), GET_X(pTp)); else if (IS_SHIP(pTp->in_room)) { SHIP_DATA *pShip; if (!(pShip = find_ship(pTp->in_room->extra_data->vnum))) strcpy(bloc, "Ship <ERROR>"); else sprintf(bloc, "Ship [%d] '%s'", pShip->vnum, pShip->name); } else if (pTp->in_room->number != NOWHERE) sprintf(bloc, "Room [%d]", pTp->in_room->number); else strcpy(bloc, "NOWHERE"); } else strcpy(bloc, "NOWHERE"); ch_printf(ch, "Trading Post %d -- Market: %d '%s'\r\n", pTp->vnum, (pTp->market ? pTp->market->vnum : NOWHERE), (pTp->market ? pTp->market->name : "<ERROR>")); ch_printf(ch, "Type: %s Location: %s\r\n", tp_type_desc[pTp->type], bloc); send_to_char("List of Goods in TP:\r\n", ch); *buf = '\0'; for (tGood = pTp->first_tpgood; tGood; tGood = tGood->next) { if (!(pGood = get_good(tGood->goods_vnum))) continue; price = 0; if (GoodsMarkets[pGood->vnum][pTp->market->vnum]) price = GoodsMarkets[pGood->vnum][pTp->market->vnum]->price; sprintf(buf+strlen(buf), " Good: [%3d] %-20s - %s Qty: %4d Price: %6d\r\n", pGood->vnum, pGood->short_descr, (tGood->stock ? "X" : " "), tGood->quantity, price); } page_string(ch->desc, buf, 0); return; } if (!isname(arg, "add free") || !*arg2 || !is_number(arg2)) { send_to_char("Valid commands for TP are: add, free\r\n", ch); return; } gnum = atoi(arg2); if (!(pGood = get_good(gnum))) { ch_printf(ch, "Invalid good vnum %d.\r\n", gnum); return; } if (is_abbrev(arg, "add")) { MARKET_GOOD *pGM; TRP_GOOD *tGood; int stock, x; if (tp_has_goods(pTp, pGood->vnum)) { send_to_char("Good already present in TP.\r\n", ch); return; } argument = one_argument(argument, arg); // get stock flag if (!*arg || !is_number(arg)) stock = 0; else stock = atoi(arg); if (stock != 1) stock = 0; if (stock && pGood->mkvnum && pGood->mkvnum != pTp->market->vnum) stock = 0; CREATE(tGood, TRP_GOOD, 1); tGood->next = NULL; tGood->prev = NULL; tGood->goods_vnum = pGood->vnum; tGood->prev_qty = 0; tGood->quantity = pGood->gtype->prod_avg[Season()] * pTp->market->var_mod.prod_var / pGood->gtype->cons_speed; tGood->stock = stock; // add good to TP good list LINK(tGood, pTp->first_tpgood, pTp->last_tpgood, next, prev); // good previously unused.. initialize. if (!pGood->mkvnum) pGood->mkvnum = pTp->market->vnum; // if not present, create GM data if (!(pGM = GoodsMarkets[pGood->vnum][pTp->market->vnum])) { CREATE(pGM, MARKET_GOOD, 1); pGM->comm_closure = 1.00; pGM->comm_prod = 1.00; pGM->demand = 0; pGM->good_appet = 1; pGM->price = pGood->cost; pGM->qty = 0; pGM->total_tp = 0; GoodsMarkets[pGood->vnum][pTp->market->vnum] = pGM; } pGM->total_tp++; pGM->qty += tGood->quantity; // perform ten resets for (x = 0; x < 10; x++) { calc_prod(pTp->market, pGood, tGood, pGM); calc_price(pTp->market, pGood, pGM); } // save new data SaveGoodsMarketsTable(0); SaveTradingPost(); send_to_char("Good succesfully added.\r\n", ch); return; } if (is_abbrev(arg, "remove")) { //MARKET_DATA *pMk; TRADING_POST *tpp; MARKET_GOOD *pGM; TRP_GOOD *tGood; if (!(tGood = tp_has_goods(pTp, pGood->vnum))) { ch_printf(ch, "Good %d is not present in TP %d.\r\n", pGood->vnum, pTp->vnum); return; } if (!(pGM = GoodsMarkets[pGood->vnum][pTp->market->vnum])) { log("SYSERR: good %d was in TP %d without GM data.\r\n", pGood->vnum, pTp->vnum); ch_printf(ch, "Good %d cannot be removed from TP %d.\r\n", pGood->vnum, pTp->vnum); return; } // look in every TP in this market for this good for (tpp = pTp->market->tp_list; tpp; tpp = tpp->next_in_market) { if ( tp_has_goods(tpp, pGood->vnum) ) break; } // good is present elsewhere, do nothing.. if (tpp) return; // remove GM info DISPOSE(GoodsMarkets[pGood->vnum][pTp->market->vnum]); // take care of GOOD info send_to_char("Good succesfully removed.\r\n", ch); return; } } /* =========================================================================== */ /* Markets Code */ /* =========================================================================== */ /* *************************************************************************** */ /* Market finding code */ /* *************************************************************************** */ MARKET_DATA *find_market(int vnum) { MARKET_DATA *pMk = NULL; for (pMk = first_market; pMk; pMk = pMk->next) { if (pMk->vnum == vnum) break; } return (pMk); } MARKET_DATA *find_market_by_name(char *mname) { MARKET_DATA *pMk = NULL; for (pMk = last_market; pMk; pMk = pMk->prev) { if (isname(mname, pMk->name)) break; } return (pMk); } /* return the lowest price of a given good in a given market */ bool get_good_in_market(MARKET_DATA *pMk, int gnum) { TRADING_POST *pTp; bool found = FALSE; // loop thru each market's trading post for (pTp = pMk->tp_list; pTp; pTp = pTp->next_in_market) { if (tp_has_goods(pTp, gnum)) { found = TRUE; break; } } return (found); } /* * trova il numero di merci del tipo specificato che * vengono prodotte nel mercato indicato */ int get_market_gtype_prod(MARKET_DATA *pMk, int gtype) { TRADING_POST *pTp; TRP_GOOD *tGood; GOOD_DATA *pGood; int amount = 0; // loop thru each trading post in given market for (pTp = pMk->tp_list; pTp; pTp = pTp->next_in_market) { // loop thru goods in trading post for (tGood = pTp->first_tpgood; tGood; tGood = tGood->next) { if (!(pGood = get_good(tGood->goods_vnum))) continue; if (pGood->code == gtype && tGood->stock) amount++; } } return (amount); } /* *************************************************************************** */ /* Market creation code */ /* *************************************************************************** */ MARKET_DATA *new_market(void) { MARKET_DATA *pMk = NULL; CREATE(pMk, MARKET_DATA, 1); pMk->next = NULL; pMk->prev = NULL; pMk->name = NULL; pMk->tp_list = NULL; pMk->affect = NULL; pMk->vnum = NOTHING; pMk->affections = 0; pMk->num_of_tp = 0; pMk->var_real.prod_var = 1.00; pMk->var_real.price_var = 1.00; pMk->var_real.closure_var = 1.00; pMk->var_mod.prod_var = 1.00; pMk->var_mod.price_var = 1.00; pMk->var_mod.closure_var = 1.00; // add to the global list LINK(pMk, first_market, last_market, next, prev); return (pMk); } /* *************************************************************************** */ /* Load Market from file code */ /* *************************************************************************** */ MARKET_DATA *fread_one_market(FILE *fp) { MARKET_DATA *pMk = new_market(); char *word; bool fMatch; for ( ; ; ) { word = feof(fp) ? "End" : fread_word(fp); fMatch = FALSE; switch (UPPER(word[0])) { case '*': fMatch = TRUE; fread_to_eol(fp); break; case 'A': if (!strcmp(word, "Affection")) { int bitv, nwhat, dur, tmp; float value; bitv = fread_number(fp); nwhat = fread_number(fp); dur = fread_number(fp); tmp = fread_number(fp); value = (float) tmp / 100; set_mk_aff(pMk->vnum, nwhat, bitv, dur, value); fMatch = TRUE; break; } break; case 'H': if (!strcmp(word, "Heart")) { pMk->heart.y = fread_number(fp); pMk->heart.x = fread_number(fp); fMatch = TRUE; break; } break; case 'E': if (!strcmp(word, "End")) return (pMk); break; case 'N': KEY("Name", pMk->name, str_dup(fread_word(fp))); break; case 'S': KEY("Size", pMk->size, fread_number(fp)); break; case 'V': KEY("Vnum", pMk->vnum, fread_number(fp)); if (!strcmp(word, "Var_real_clos")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_real.closure_var = calc; fMatch = TRUE; break; } if (!strcmp(word, "Var_real_prod")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_real.prod_var = calc; fMatch = TRUE; break; } if (!strcmp(word, "Var_real_price")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_real.price_var = calc; fMatch = TRUE; break; } /* if (!strcmp(word, "Var_mod_clos")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_mod.closure_var = calc; fMatch = TRUE; break; } if (!strcmp(word, "Var_mod_prod")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_mod.prod_var = calc; fMatch = TRUE; break; } if (!strcmp(word, "Var_mod_price")) { int num; float calc; num = fread_number(fp); calc = (float)num / 100; pMk->var_mod.price_var = calc; fMatch = TRUE; break; } */ break; } if (!fMatch) log("fread_one_market: no match: %s", word); } return (NULL); } void LoadMarkets(void) { FILE *fp; char fname[128]; char letter; char *word; sprintf(fname, "%smarkets.data", LIB_GOODS); if (!(fp = fopen(fname, "r"))) { log("SYSERR: LoadMarkets() - cannot open file %s.", fname); return; } for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (feof(fp)) break; if (letter != '#') { log("SYSERR: LoadMarkets() - # not found."); break; } word = fread_word(fp); if (!strcmp(word, "MARKET")) { if (!fread_one_market(fp)) { log("SYSERR: LoadMarkets() - error in reading market."); fclose(fp); exit(1); } } else if (!strcmp( word, "END")) // Done break; else { log("SYSERR: LoadMarkets() - bad section %s", word); continue; } } fclose(fp); } /* *************************************************************************** */ /* Save Market to file code */ /* *************************************************************************** */ void SaveMarkets(void) { FILE *fp; MARKET_DATA *pMk; char fname[128]; if (!first_market) return; sprintf(fname, "%smarkets.data", LIB_GOODS); if (!(fp = fopen(fname, "w"))) { log("SYSERR: SaveMarkets() - cannot open file %s.", fname); return; } for (pMk = first_market; pMk; pMk = pMk->next) { fprintf(fp, "#MARKET\n"); fprintf(fp, "Vnum %d\n", pMk->vnum); fprintf(fp, "Name %s\n", pMk->name); fprintf(fp, "Heart %hd %hd\n", pMk->heart.y, pMk->heart.x); fprintf(fp, "Size %d\n", pMk->size); fprintf(fp, "Var_real_clos %d\n", (int)(pMk->var_real.closure_var * 100)); fprintf(fp, "Var_real_prod %d\n", (int)(pMk->var_real.prod_var * 100)); fprintf(fp, "Var_real_price %d\n", (int)(pMk->var_real.price_var * 100)); // fprintf(fp, "Var_mod_clos %d\n", (int)(pMk->var_mod.closure_var * 100)); // fprintf(fp, "Var_mod_prod %d\n", (int)(pMk->var_mod.prod_var * 100)); // fprintf(fp, "Var_mod_price %d\n", (int)(pMk->var_mod.price_var * 100)); if (pMk->affect) { MARKET_AFF *pAff = NULL; for (pAff = pMk->affect; pAff; pAff = pAff->next) { fprintf(fp, "Affection %d %hd %hd %d\n", pAff->bitvector, pAff->what, pAff->duration, (int)(pAff->modifier * 100)); } } fprintf(fp, "End\n\n"); } fprintf(fp, "#END\n"); fclose(fp); } /* *************************************************************************** */ /* Market Affections code */ /* *************************************************************************** */ NAME_NUMBER mk_gdr_aff[] = { {"pestilence", MKT_PESTILENCE}, {"insects", MKT_INSECT}, {"drought", MKT_DROUGHT}, {"flood", MKT_FLOOD}, {"war", MKT_WAR}, {"\n", 0} }; NAME_NUMBER mk_gdr_modif[] = { {"production", MOD_PROD}, {"price", MOD_PRICE}, {"closure", MOD_CLOSURE}, {"\n", 0} }; const char *mk_aff_descr[] = { "EXTRA_PROD", "MALUS_PROD", "EXTRA_PRICE", "MALUS_PRICE", "PESTILENCE", "INSECTS", "DROUGHT", "FLOOD", "WAR", "\n" }; const char *mk_aff_what[] = { "NONE", "PRODUCTION", "PRICE", "CLOSURE", "\n" }; void affect_to_market(MARKET_DATA *pMk, MARKET_AFF *pAff) { // set affection bitvector SET_BIT(pMk->affections, pAff->bitvector); // apply value modification switch (pAff->what) { case MOD_CLOSURE: pMk->var_mod.closure_var += pAff->modifier; break; case MOD_PROD: pMk->var_mod.prod_var += pAff->modifier; break; case MOD_PRICE: pMk->var_mod.price_var += pAff->modifier; break; } // add to the list pAff->next = pMk->affect; pMk->affect = pAff; } void affect_from_market(MARKET_DATA *pMk, MARKET_AFF *pAff) { MARKET_AFF *temp = NULL; // remove affection bitvector REMOVE_BIT(pMk->affections, pAff->bitvector); // undo value modification switch (pAff->what) { case MOD_CLOSURE: pMk->var_mod.closure_var -= pAff->modifier; break; case MOD_PROD: pMk->var_mod.prod_var -= pAff->modifier; break; case MOD_PRICE: pMk->var_mod.price_var -= pAff->modifier; break; } // remove from the list REMOVE_FROM_LIST(pAff, pMk->affect, next); pAff->next = NULL; // take care DISPOSE(pAff); } MARKET_AFF *market_aff_by_bitv(MARKET_DATA *pMk, int bitv) { MARKET_AFF *pAff = NULL; for (pAff = pMk->affect; pAff; pAff = pAff->next) if (pAff->bitvector == bitv) break; return (pAff); } void set_mk_aff(int mnum, int nwhat, int bitv, int durat, float value) { MARKET_DATA *pMk; MARKET_AFF *pAff = NULL; if (!(pMk = find_market(mnum))) return; pAff = market_aff_by_bitv(pMk, bitv); // it's not there... setup a new one if (!pAff || pAff->what != nwhat) { CREATE(pAff, MARKET_AFF, 1); pAff->next = NULL; pAff->bitvector = bitv; pAff->duration = durat; pAff->modifier = value; pAff->what = nwhat; affect_to_market(pMk, pAff); } // update existing affection else { if (durat != MUD_DAYS_PER_YEAR) pAff->duration += durat; pAff->modifier += value; // apply value modification switch (pAff->what) { case MOD_CLOSURE: pMk->var_mod.closure_var += value; break; case MOD_PROD: pMk->var_mod.prod_var += value; break; case MOD_PRICE: pMk->var_mod.price_var += value; break; } } } // called every mud day void UpdateMarketAffections(void) { MARKET_DATA *pMk; MARKET_AFF *pAff = NULL, *pAff_next = NULL; for (pMk = first_market; pMk; pMk = pMk->next) { for (pAff = pMk->affect; pAff; pAff = pAff_next) { pAff_next = pAff->next; if (pAff->duration == -1) continue; if (--pAff->duration <= 0) affect_from_market(pMk, pAff); } } SaveMarkets(); } /* automatic affections.. rolled once every three mud months... */ void RollMarketAffections(void) { MARKET_DATA *pMk; int type, bitv, dur, nwhat; float value = 0; //char dflags[128], swhat[128]; for (pMk = first_market; pMk; pMk = pMk->next) { if (!pMk->size) continue; for (type = 0; type < 4; type++) { if (number(1, 12) > 1) continue; bitv = (1 << type); dur = MUD_DAYS_PER_YEAR; switch (type) { case 0: nwhat = MOD_PROD; value = 0.1F; break; case 1: nwhat = MOD_PROD; value = -0.1F; break; case 2: nwhat = MOD_PRICE; value = 0.1F; break; case 3: nwhat = MOD_PRICE; value = -0.1F; break; } set_mk_aff(pMk->vnum, nwhat, bitv, dur, value); //sprintbit(bitv, mk_aff_descr, dflags); //sprinttype(nwhat, mk_aff_what, swhat); //log("Economy - settata auto affection %s (mod %s) sul mercato %d.", // dflags, swhat, pMk->vnum); } } } // print info on markets ACMD(do_market) { MARKET_DATA *pMk; MARKET_GOOD *pGM; char arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH]; int gn; argument = one_argument(argument, arg); if (!*arg) { send_to_char( "Usage:\r\n" "-----------------------------------------------------------------------\r\n" " command description\r\n" "-----------------------------------------------------------------------\r\n" " market list List of markets in game.\r\n" " market info Show global trade and production info\r\n" " market <vnum> <gm> Detailed info for market <vnum>\r\n" " market <name> <gm> Detailed info for market <name>\r\n" "-----------------------------------------------------------------------\r\n" " <gm> if any data is present print Goods/Markets info\r\n" "-----------------------------------------------------------------------\r\n" , ch); return; } if (!str_cmp(arg, "info")) { extern char *newspaper; if (newspaper) page_string(ch->desc, newspaper, 0); else send_to_char("Trade Newspaper not present.\r\n", ch); return; } if (!str_cmp(arg, "list")) { send_to_char("Current markets in game:\r\n", ch); for (pMk = first_market; pMk; pMk = pMk->next) { if (!pMk->size) continue; ch_printf(ch, "[%d] %-30s - Center: [%4d %4d]\r\n", pMk->vnum, pMk->name, pMk->heart.y, pMk->heart.x); } return; } if (is_number(arg)) { if (!(pMk = find_market(atoi(arg)))) { ch_printf(ch, "There isn't a market with vnum %d.\r\n", atoi(arg)); return; } } else { if (!(pMk = find_market_by_name(arg))) { ch_printf(ch, "There isn't a market called '%s'.\r\n", arg); return; } } //extra check if (!pMk) return; sprintf(buf, "Market [%d] %s\r\n", pMk->vnum, pMk->name); sprintf(buf + strlen(buf), "Heart coord: [%4d %4d] Size: %d\r\n", pMk->heart.y, pMk->heart.x, pMk->size); sprintf(buf + strlen(buf), "Number of Trading Posts: %d\r\n", pMk->num_of_tp); sprintf(buf + strlen(buf), "Default Modifier - Prod: [%5.2f] Price: [%5.2f] Clos: [%5.2f]\r\n", pMk->var_real.prod_var, pMk->var_real.price_var, pMk->var_real.closure_var); sprintf(buf + strlen(buf), "Current Modifier - Prod: [%5.2f] Price: [%5.2f] Clos: [%5.2f]\r\n", pMk->var_mod.prod_var, pMk->var_mod.price_var, pMk->var_mod.closure_var); send_to_char(buf, ch); if (pMk->affect) { MARKET_AFF *pAff = NULL; char dflags[128], swhat[128]; sprintf(buf, "Affections:\r\n"); for (pAff = pMk->affect; pAff; pAff = pAff->next) { sprintbit(pAff->bitvector, mk_aff_descr, dflags); sprinttype(pAff->what, mk_aff_what, swhat); sprintf(buf+strlen(buf), " Bit: [%-12s] Modif: [%-12s] Duration: [%4d] Value: [%5.2f]\r\n", dflags, swhat, pAff->duration, pAff->modifier); } send_to_char(buf, ch); } argument = one_argument(argument, arg); if (!*arg) return; sprintf(buf, "Goods / Market Info:\r\n"); for (gn = 0; gn < MAX_GOOD; gn++) { if (!(pGM = GoodsMarkets[gn][pMk->vnum])) continue; sprintf(buf+strlen(buf), " Good: [%3d] - Qty:[%5d] Price:[%5d] Demand:[%5.2f]\r\n", gn, pGM->qty, pGM->price, pGM->demand); } send_to_char(buf, ch); } // allow imms to set gdr affections on markets ACMD(do_mkaff) { MARKET_DATA *pMk; char arg[MAX_INPUT_LENGTH]; int nr; int bitv = 0, modif = 0, dur = 0; float value = 0; argument = one_argument(argument, arg); if (!*arg) { send_to_char("Usage: mkaff <market> <affection> <modif> <duration> <value>\r\n", ch); return; } // get market if (is_number(arg)) { if (!(pMk = find_market(atoi(arg)))) { ch_printf(ch, "There isn't a market with vnum %d.\r\n", atoi(arg)); return; } } else { if (!(pMk = find_market_by_name(arg))) { ch_printf(ch, "There isn't a market called '%s'.\r\n", arg); return; } } // get affection argument = one_argument(argument, arg); if (!*arg) { send_to_char("Available affections are:\r\n", ch); for (nr = 0; *mk_gdr_aff[nr].name != '\n'; nr++) ch_printf(ch, "%s\r\n", mk_gdr_aff[nr].name); return; } for (nr = 0; *mk_gdr_aff[nr].name != '\n'; nr++) { if ( isname(arg, mk_gdr_aff[nr].name) ) break; } if (*mk_gdr_aff[nr].name == '\n') { send_to_char("Unknown affection.\r\nAvailable affections are:\r\n", ch); for (nr = 0; *mk_gdr_aff[nr].name != '\n'; nr++) ch_printf(ch, "%s\r\n", mk_gdr_aff[nr].name); return; } bitv = mk_gdr_aff[nr].number; // get modifier argument = one_argument(argument, arg); if (!*arg) { send_to_char("Available modifiers are:\r\n", ch); for (nr = 0; *mk_gdr_modif[nr].name != '\n'; nr++) ch_printf(ch, "%s\r\n", mk_gdr_modif[nr].name); return; } for (nr = 0; *mk_gdr_modif[nr].name != '\n'; nr++) { if ( isname(arg, mk_gdr_modif[nr].name) ) break; } if (*mk_gdr_modif[nr].name == '\n') { send_to_char("Unknown modifier.\r\nAvailable modifiers are:\r\n", ch); for (nr = 0; *mk_gdr_modif[nr].name != '\n'; nr++) ch_printf(ch, "%s\r\n", mk_gdr_modif[nr].name); return; } modif = mk_gdr_modif[nr].number; // get duration argument = one_argument(argument, arg); if (!*arg || !is_number(arg)) { ch_printf(ch, "Duration must be a number from 1 to %d\r\n", MUD_DAYS_PER_YEAR); return; } dur = atoi(arg); if (dur < 1 || dur > MUD_DAYS_PER_YEAR) { ch_printf(ch, "Duration must be a number from 1 to %d\r\n", MUD_DAYS_PER_YEAR); return; } // get value.. handle decimals.. argument = one_argument(argument, arg); if (!*arg) { send_to_char("Value must be a number from -2.0 to 2.0\r\n", ch); return; } value = atof(arg); if (value < -2.0 || value > 2.0) { send_to_char("Value must be a number from -2.0 to 2.0\r\n", ch); return; } set_mk_aff(pMk->vnum, modif, bitv, dur, value); send_to_char("Done.\r\n", ch); SaveMarkets(); } ACMD(do_goodinfo) { GOOD_DATA *pGood; MARKET_DATA *pMk; MARKET_GOOD *pGM; char arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH]; int gn, mn, price; one_argument(argument, arg); if (!*arg || !is_number(arg)) { send_to_char("Usage: ginfo <good vnum>\r\n", ch); return; } gn = atoi(arg); if (!(pGood = get_good(gn))) { ch_printf(ch, "There is no good with vnum %d.\r\n", gn); return; } sprintf(buf, "Good: '%s' [%d]\r\n", pGood->name, gn); sprintf(buf+strlen(buf), "Unit: %s Weigth: %d Cost: %d\r\n", pGood->unit, pGood->weight, pGood->cost); sprintf(buf+strlen(buf), "Type: (%d) %s\r\n", pGood->gtype->vnum, pGood->gtype->name); sprintf(buf+strlen(buf), "Cons_speed: %6.2f Elasticity: %d\r\n", pGood->gtype->cons_speed, pGood->gtype->elasticity); sprintf(buf+strlen(buf), "Production: Wn:%d Sp:%d Sm:%d At:%d\r\n", pGood->gtype->prod_avg[0], pGood->gtype->prod_avg[1], pGood->gtype->prod_avg[2], pGood->gtype->prod_avg[3]); send_to_char(buf, ch); ch_printf(ch, "Commercial data:\r\n", pGood->name, gn); for (mn = 0; mn < MAX_MARKET; mn++) { if (!(pMk = find_market(mn))) continue; if (!str_cmp(pMk->name, "noname") || !pMk->size) continue; price = calc_trade_value(gn, mn); if (!(pGM = GoodsMarkets[gn][mn])) sprintf(buf, " Market: [%3d] %-15s - Qty: [%5d] Sell Price: [%4d] Buy Price: [%4d] Demand: [%6.2f]\r\n", mn, pMk->name, 0, 0, price, 0); else sprintf(buf, " Market: [%3d] %-15s - Qty: [%5d] Sell Price: [%4d] Buy Price: [%4d] Demand: [%6.2f]\r\n", mn, pMk->name, pGM->qty, pGM->price, price, pGM->demand); send_to_char(buf, ch); } } /* =========================================================================== */ /* Trading Code */ /* =========================================================================== */ /* *************************************************************************** */ /* Boot Setup Market-Goods data code */ /* *************************************************************************** */ void SaveGoodsMarketsTable(bool bTime) { FILE *fp; MARKET_GOOD *pGM; GOOD_DATA *pGood; MARKET_DATA *pMk; char fname[128]; int gn, mn; if (bTime) { sprintf(fname, "%sgoodsmarkets.txt", LIB_GOODS); fp = fopen(fname, "a+"); } else { sprintf(fname, "%sgoodsmarkets.data", LIB_GOODS); fp = fopen(fname, "w"); } if (!fp) { log("SYSERR: SaveGoodsMarketsTable() - cannot open file %s.", fname); return; } for (mn = 0; mn < MAX_MARKET; mn++) { pMk = find_market(mn); for (gn = 0; gn < MAX_GOOD; gn++) { if (!(pGM = GoodsMarkets[gn][mn])) continue; if (!(pGood = get_good(gn))) continue; if (bTime) { double calc = 0; if (pGM->qty && pGM->total_tp) calc = (double) pGM->qty / pGM->total_tp; fprintf(fp, "G:%ld M:%ld [C:%4.2f P:%4.2f PP:%4.2f] (Stock=%d) : Qty=[%-4ld] Price=[%-4ld] Qty/TP=[%7.2f] Comm_prod=[%7.2f] Demand=[%7.2f]\n", gn, mn, pMk->var_mod.closure_var, pMk->var_mod.prod_var, pMk->var_mod.price_var, (pGood->mkvnum == mn ? 1 : 0), pGM->qty, pGM->price, calc, pGM->comm_prod, pGM->demand); } else { fprintf(fp, "#GM %d %d %d %d %d %hd %d %d\n", mn, gn, (int)(pGM->demand * 100), 0, pGM->price, pGM->good_appet, (int)(pGM->comm_prod * 100), (int)(pGM->comm_closure * 100) ); } } } if (!bTime) { fprintf(fp, "#END\n"); fclose(fp); return; } for (mn = 0; mn < MAX_MARKET; mn++) { for (gn = 0; gn < MAX_GOOD; gn++) { if (!(pGM = GoodsMarkets[gn][mn])) continue; { double calc = 0; if (pGM->qty && pGM->total_tp) calc = (double) pGM->qty / pGM->total_tp; fprintf(fp, "%ld;%ld;%ld;%ld;%f;%f\n", mn, gn, pGM->qty, pGM->price, calc, pGM->comm_prod); } } } fprintf(fp, "#END\n"); fclose(fp); } void LoadGoodsMarketsTable(void) { FILE *fp; char fname[128]; char letter; char *word; int gn, mn; sprintf(fname, "%sgoodsmarkets.data", LIB_GOODS); if (!(fp = fopen(fname, "r"))) { log("SYSERR: LoadGoodsMarketsTable() - cannot open file %s.", fname); reset_markets = 1; return; } for ( ; ; ) { letter = fread_letter(fp); if (letter == '*') { fread_to_eol(fp); continue; } if (feof(fp)) break; if (letter != '#') { log("SYSERR: LoadGoodsMarketsTable() - # not found."); break; } word = fread_word(fp); if (!strcmp(word, "GM")) { int num; float calc; mn = fread_number(fp); if (mn < 0 || mn > MAX_MARKET) { log("SYSERR: invalid market number %d.", mn); exit(1); } gn = fread_number(fp); if (gn < 0 || gn > MAX_GOOD) { log("SYSERR: invalid good number %d.", gn); exit(1); } if (GoodsMarkets[gn][mn]) { log("SYSERR: LoadGoodsMarketsTable() - duplicate GoodsMarkets info for G:%d M:%d.", gn, mn); GoodsMarkets[gn][mn]->demand = 0.0; GoodsMarkets[gn][mn]->qty = 0; GoodsMarkets[gn][mn]->price = 0; GoodsMarkets[gn][mn]->comm_closure = 0.0; GoodsMarkets[gn][mn]->comm_prod = 0.0; GoodsMarkets[gn][mn]->good_appet = 0; } else CREATE(GoodsMarkets[gn][mn], MARKET_GOOD, 1); num = fread_number(fp); calc = (float)num / 100; GoodsMarkets[gn][mn]->demand = calc; GoodsMarkets[gn][mn]->qty = fread_number(fp); GoodsMarkets[gn][mn]->price = fread_number(fp); GoodsMarkets[gn][mn]->good_appet = fread_number(fp); num = fread_number(fp); calc = (float)num / 100; GoodsMarkets[gn][mn]->comm_prod = calc; num = fread_number(fp); calc = (float)num / 100; GoodsMarkets[gn][mn]->comm_closure = calc; } else if (!strcmp( word, "END")) // Done break; else { log("SYSERR: LoadGoodsMarketsTable() - bad section %s", word); continue; } } fclose(fp); } void BootMarkets(void) { reset_markets = 0; LoadMarkets(); LoadGoodsMarketsTable(); } /* * su "mercato x" la produzione e' "0-1 = buona, 1-2= alta, 3-4 = altissima, * -1,0 = bassa, -1 -2 = bassissima, -2 -4 = pessima" ed i prezzi sono "0-1 = buoni, * 1-2= alti, 3-4 = altissimi, -1,0 = bassi, -1 -2 = bassissimi, -2 -4 = pessimi"... * o qualcosa di simile... */ extern char *newspaper; const char *trade_descr[] = { "bad", // -4 -2 "low", // -2 -1 "poor", // -1 0 "normal", // 0 1 "good", // 1 2 "high" // 2 4 }; int trade_descr_index(float val) { int idx; if (val < -2) idx = 0; else if (val < -1) idx = 1; else if (val < 0) idx = 2; else if (val <= 1) idx = 3; else if (val < 2) idx = 4; else idx = 5; return (idx); } void update_newspaper(void) { FILE *fp; MARKET_DATA *pMk; int iprod, iprice; if (!(fp = fopen(NEWSPAPER_FILE, "w"))) return; fprintf(fp, "Market Production Prices\n" "---------------------------------------------------------------------------\n"); for (pMk = first_market; pMk; pMk = pMk->next) { // skip unused markets if (!pMk->size) continue; iprod = trade_descr_index(pMk->var_mod.prod_var); iprice = trade_descr_index(pMk->var_mod.price_var); fprintf(fp, "%-25s %-15s [%6.2f] %-15s [%6.2f]\n", pMk->name, trade_descr[iprod], pMk->var_mod.prod_var, trade_descr[iprice], pMk->var_mod.price_var ); } fprintf(fp, "---------------------------------------------------------------------------\n"); fclose(fp); } int file_to_string_alloc(const char *name, char **buf); ACMD(do_newspaper) { update_newspaper(); file_to_string_alloc(NEWSPAPER_FILE, &newspaper); }