| version 1.27 | | version 1.28 |
|---|
| | |
| /* | | /* |
| * static char *rcsid_shop_c = | | * static char *rcsid_shop_c = |
| * "$Id: shop.c,v 1.27 2004/04/16 16:28:22 akirschbaum Exp $"; | | * "$Id: shop.c,v 1.28 2004/04/25 07:17:40 mwedel Exp $"; |
| */ | | */ |
| | | |
| /* | | /* |
| | |
| * | | * |
| * Mark Wedel (mwedel@pyramid.com) | | * Mark Wedel (mwedel@pyramid.com) |
| */ | | */ |
| int query_cost(object *tmp, object *who, int flag) { | | uint64 query_cost(object *tmp, object *who, int flag) { |
| int val; | | uint64 val; |
| int number; /* used to better calculate value */ | | int number; /* used to better calculate value */ |
| int no_bargain; | | int no_bargain; |
| float diff; | | float diff; |
| | |
| /* Limit amount of money you can get for really great items. */ | | /* Limit amount of money you can get for really great items. */ |
| if (flag==F_TRUE || flag==F_SELL) { | | if (flag==F_TRUE || flag==F_SELL) { |
| if (val/number>10000) { | | if (val/number>10000) { |
| val=8000+isqrt((int)val/number)*20; | | val=8000+isqrt(val/number)*20; |
| val *= number; | | val *= number; |
| } | | } |
| } | | } |
| | |
| if(flag==F_SELL && !QUERY_FLAG(tmp, FLAG_IDENTIFIED) && need_identify(tmp)) { | | if(flag==F_SELL && !QUERY_FLAG(tmp, FLAG_IDENTIFIED) && need_identify(tmp)) { |
| val = (val > 600)? 600:val; | | val = (val > 600)? 600:val; |
| } | | } |
| return (int)val; | | return val; |
| } | | } |
| | | |
| /* Find the coin type that is worth more the 'c'. Starts at the | | /* Find the coin type that is worth more the 'c'. Starts at the |
| * cointype placement. | | * cointype placement. |
| */ | | */ |
| | | |
| static archetype *find_next_coin(int c, int *cointype) { | | static archetype *find_next_coin(uint64 c, int *cointype) { |
| archetype *coin; | | archetype *coin; |
| | | |
| do { | | do { |
| | |
| return coin; | | return coin; |
| } | | } |
| | | |
| /* This returns a string of how much somethign is worth based on | | /* This returns a string of how much something is worth based on |
| * an integer being passed. | | * an integer being passed. |
| | | * cost is the cost we need to represent. |
| | | * While cost is 64 bit, the number of any coin is still really |
| | | * limited to 32 bit (size of nrof field). If it turns out players |
| | | * have so much money that they have more than 2 billion platinum |
| | | * coins, there are certainly issues - the easiest fix at that |
| | | * time is to add a higher denomination (mithril piece with |
| | | * 10,000 silver or something) |
| */ | | */ |
| char *cost_string_from_value(int cost) | | char *cost_string_from_value(uint64 cost) |
| { | | { |
| static char buf[MAX_BUF]; | | static char buf[MAX_BUF]; |
| archetype *coin, *next_coin; | | archetype *coin, *next_coin; |
| | |
| return "nothing"; | | return "nothing"; |
| | | |
| num = cost / coin->clone.value; | | num = cost / coin->clone.value; |
| cost -= num * coin->clone.value; | | /* so long as nrof is 32 bit, this is true. |
| | | * If it takes more coins than a person can possibly carry, this |
| | | * is basically true. |
| | | */ |
| | | if ( (cost / coin->clone.value) > UINT32_MAX) { |
| | | strcpy(buf,"an unimaginable sum of money."); |
| | | return buf; |
| | | } |
| | | |
| | | cost -= (uint64)num * (uint64)coin->clone.value; |
| if (num == 1) | | if (num == 1) |
| sprintf(buf, "1 %s", coin->clone.name); | | sprintf(buf, "1 %s", coin->clone.name); |
| else | | else |
| | |
| | | |
| coin = next_coin; | | coin = next_coin; |
| num = cost / coin->clone.value; | | num = cost / coin->clone.value; |
| cost -= num * coin->clone.value; | | cost -= (uint64)num * (uint64)coin->clone.value; |
| | | |
| if (cost == 0) | | if (cost == 0) |
| next_coin = NULL; | | next_coin = NULL; |
| | |
| return cost_string_from_value(query_cost(tmp,who,flag)); | | return cost_string_from_value(query_cost(tmp,who,flag)); |
| } | | } |
| | | |
| /* This function finds out how much money the player is carrying, * | | /* This function finds out how much money the player is carrying, |
| * and returns that value */ | | * including what is in containers. |
| /* Now includes any coins in active containers -- DAMN */ | | */ |
| int query_money(object *op) { | | uint64 query_money(object *op) { |
| object *tmp; | | object *tmp; |
| int total=0; | | uint64 total=0; |
| | | |
| if (op->type!=PLAYER && op->type!=CONTAINER) { | | if (op->type!=PLAYER && op->type!=CONTAINER) { |
| LOG(llevError, "Query money called with non player/container"); | | LOG(llevError, "Query money called with non player/container"); |
| | |
| } | | } |
| for (tmp = op->inv; tmp; tmp= tmp->below) { | | for (tmp = op->inv; tmp; tmp= tmp->below) { |
| if (tmp->type==MONEY) { | | if (tmp->type==MONEY) { |
| total += tmp->nrof * tmp->value; | | total += (uint64)tmp->nrof * (uint64)tmp->value; |
| } else if (tmp->type==CONTAINER && | | } else if (tmp->type==CONTAINER && |
| QUERY_FLAG(tmp,FLAG_APPLIED) && | | QUERY_FLAG(tmp,FLAG_APPLIED) && |
| (tmp->race==NULL || strstr(tmp->race,"gold"))) { | | (tmp->race==NULL || strstr(tmp->race,"gold"))) { |
| | |
| } | | } |
| return total; | | return total; |
| } | | } |
| /* TCHIZE: This function takes the amount of money from the * | | /* TCHIZE: This function takes the amount of money from the |
| * the player inventory and from it's various pouches using the * | | * the player inventory and from it's various pouches using the |
| * pay_from_container function. * | | * pay_from_container function. |
| * returns 0 if not possible. 1 if success */ | | * returns 0 if not possible. 1 if success |
| | | */ |
| int pay_for_amount(int to_pay,object *pl) { | | int pay_for_amount(int to_pay,object *pl) { |
| object *pouch; | | object *pouch; |
| | | |
| | |
| return 1; | | return 1; |
| } | | } |
| | | |
| /* DAMN: This is now a wrapper for pay_from_container, which is * | | /* DAMN: This is now a wrapper for pay_from_container, which is |
| * called for the player, then for each active container that can hold * | | * called for the player, then for each active container that can hold |
| * money until op is paid for. Change will be left wherever the last * | | * money until op is paid for. Change will be left wherever the last |
| * of the price was paid from. */ | | * of the price was paid from. |
| | | */ |
| int pay_for_item(object *op,object *pl) { | | int pay_for_item(object *op,object *pl) { |
| int to_pay = query_cost(op,pl,F_BUY); | | uint64 to_pay = query_cost(op,pl,F_BUY); |
| object *pouch; | | object *pouch; |
| int saved_money; | | uint64 saved_money; |
| | | |
| if (to_pay==0) return 1; | | if (to_pay==0) return 1; |
| if(to_pay>query_money(pl)) return 0; | | if(to_pay>query_money(pl)) return 0; |
| | |
| * with weight not be subtracted properly. We now remove and | | * with weight not be subtracted properly. We now remove and |
| * insert the coin objects - this should update the weight | | * insert the coin objects - this should update the weight |
| * appropriately | | * appropriately |
| | | * |
| | | * DAMN: This function is used for the player, then for any active |
| | | * containers that can hold money, until the op is paid for. |
| */ | | */ |
| /* DAMN: This function is used for the player, then for any active * | | uint64 pay_from_container(object *op, object *pouch, int to_pay) { |
| * containers that can hold money, until the op is paid for. */ | | int count, i; |
| int pay_from_container(object *op, object *pouch, int to_pay) { | | uint64 remain; |
| int count, i, remain; | | |
| object *tmp, *coin_objs[NUM_COINS], *next; | | object *tmp, *coin_objs[NUM_COINS], *next; |
| archetype *at; | | archetype *at; |
| object *who; | | object *who; |
| | |
| | | |
| if (coin_objs[i]->nrof*coin_objs[i]->value> remain) { | | if (coin_objs[i]->nrof*coin_objs[i]->value> remain) { |
| num_coins = remain / coin_objs[i]->value; | | num_coins = remain / coin_objs[i]->value; |
| if (num_coins*coin_objs[i]->value< remain) num_coins++; | | if ((uint64)num_coins*(uint64)coin_objs[i]->value < remain) num_coins++; |
| } else { | | } else { |
| num_coins = coin_objs[i]->nrof; | | num_coins = coin_objs[i]->nrof; |
| } | | } |
| | | |
| remain -= num_coins * coin_objs[i]->value; | | remain -= (uint64)num_coins * (uint64)coin_objs[i]->value; |
| coin_objs[i]->nrof -= num_coins; | | coin_objs[i]->nrof -= num_coins; |
| /* Now start making change. Start at the coin value | | /* Now start making change. Start at the coin value |
| * below the one we just did, and work down to | | * below the one we just did, and work down to |
| | |
| for (i=0; i<NUM_COINS; i++) { | | for (i=0; i<NUM_COINS; i++) { |
| if (coin_objs[i]->nrof) { | | if (coin_objs[i]->nrof) { |
| object *tmp = insert_ob_in_ob(coin_objs[i], pouch); | | object *tmp = insert_ob_in_ob(coin_objs[i], pouch); |
| for (who = pouch; who && who->type!=PLAYER && who->env!=NULL; who=who->env) {} | | for (who = pouch; who && who->type!=PLAYER && who->env!=NULL; who=who->env) ; |
| esrv_send_item(who, tmp); | | esrv_send_item(who, tmp); |
| esrv_send_item (who, pouch); | | esrv_send_item (who, pouch); |
| esrv_update_item (UPD_WEIGHT, who, pouch); | | esrv_update_item (UPD_WEIGHT, who, pouch); |
| | |
| return(remain); | | return(remain); |
| } | | } |
| | | |
| /* Eneq(@csd.uu.se): Better get_payment, descends containers looking for | | /* Better get_payment, descends containers looking for |
| unpaid items. get_payment is now used as a link. To make it simple | | * unpaid items, and pays for them. |
| we need the player-object here. */ | | * returns 0 if the player still has unpaid items. |
| | | * returns 1 if the player has paid for everything. |
| int get_payment2 (object *pl, object *op) { | | * pl is the player buying the stuff. |
| | | * op is the object we are examining. If op has |
| | | * and inventory, we examine that. IF there are objects |
| | | * below op, we descend down. |
| | | */ |
| | | int get_payment(object *pl, object *op) { |
| char buf[MAX_BUF]; | | char buf[MAX_BUF]; |
| int ret=1; | | int ret=1; |
| | | |
| if (op!=NULL&&op->inv) | | if (op!=NULL&&op->inv) |
| ret = get_payment2(pl, op->inv); | | ret = get_payment(pl, op->inv); |
| | | |
| if (!ret) | | if (!ret) |
| return 0; | | return 0; |
| | | |
| if (op!=NULL&&op->below) | | if (op!=NULL&&op->below) |
| ret = get_payment2 (pl, op->below); | | ret = get_payment (pl, op->below); |
| | | |
| if (!ret) | | if (!ret) |
| return 0; | | return 0; |
| | |
| if(op!=NULL&&QUERY_FLAG(op,FLAG_UNPAID)) { | | if(op!=NULL&&QUERY_FLAG(op,FLAG_UNPAID)) { |
| strncpy(buf,query_cost_string(op,pl,F_BUY),MAX_BUF); | | strncpy(buf,query_cost_string(op,pl,F_BUY),MAX_BUF); |
| if(!pay_for_item(op,pl)) { | | if(!pay_for_item(op,pl)) { |
| int i=query_cost(op,pl,F_BUY) - query_money(pl); | | uint64 i=query_cost(op,pl,F_BUY) - query_money(pl); |
| CLEAR_FLAG(op, FLAG_UNPAID); | | CLEAR_FLAG(op, FLAG_UNPAID); |
| new_draw_info_format(NDI_UNIQUE, 0, pl, | | new_draw_info_format(NDI_UNIQUE, 0, pl, |
| "You lack %s to buy %s.", cost_string_from_value(i), | | "You lack %s to buy %s.", cost_string_from_value(i), |
| | |
| return 1; | | return 1; |
| } | | } |
| | | |
| int get_payment(object *pl) { | | |
| int ret; | | |
| | | |
| ret = get_payment2 (pl, pl->inv); | | /* Modified function to give out platinum coins. This function uses |
| | | * the coins[] array to know what coins are available, just like |
| return ret; | | * buy item. |
| } | | * |
| | | * Modified to fill available race: gold containers before dumping |
| /* Modified function to give out platinum coins. This function is * | | * remaining coins in character's inventory. |
| * not as general as pay_for_item in finding money types - each * | | */ |
| * new money type needs to be explicity code in here. */ | | |
| /* Modified to fill available race: gold containers before dumping * | | |
| * remaining coins in character's inventory. -- DAMN */ | | |
| void sell_item(object *op, object *pl) { | | void sell_item(object *op, object *pl) { |
| int i=query_cost(op,pl,F_SELL), count; | | uint64 i=query_cost(op,pl,F_SELL), extra_gain; |
| object *tmp; | | int count; |
| object *pouch; | | object *tmp, *pouch; |
| archetype *at; | | archetype *at; |
| int extra_gain; | | |
| | | |
| if(pl==NULL||pl->type!=PLAYER) { | | if(pl==NULL||pl->type!=PLAYER) { |
| LOG(llevDebug,"Object other than player tried to sell something.\n"); | | LOG(llevDebug,"Object other than player tried to sell something.\n"); |
| | |
| identify(op); | | identify(op); |
| return; | | return; |
| } | | } |
| | | |
| /* We compare the price with the one for a player | | /* We compare the price with the one for a player |
| * without bargaining skill. | | * without bargaining skill. |
| * This determins the amount of exp (if any) gained for bargaining. | | * This determins the amount of exp (if any) gained for bargaining. |
| | |
| | | |
| if (w==0) w=1; /* Prevent divide by zero */ | | if (w==0) w=1; /* Prevent divide by zero */ |
| if ( n>0 && (!pouch->weight_limit || pouch->carrying+w<=pouch->weight_limit)) { | | if ( n>0 && (!pouch->weight_limit || pouch->carrying+w<=pouch->weight_limit)) { |
| if (pouch->weight_limit && (pouch->weight_limit-pouch->carrying)/w<n) { | | if (pouch->weight_limit && (pouch->weight_limit-pouch->carrying)/w<n) |
| n = (pouch->weight_limit-pouch->carrying)/w; | | n = (pouch->weight_limit-pouch->carrying)/w; |
| } | | |
| tmp = get_object(); | | tmp = get_object(); |
| copy_object(&at->clone, tmp); | | copy_object(&at->clone, tmp); |
| tmp->nrof = n; | | tmp->nrof = n; |
| i -= tmp->nrof * tmp->value; | | i -= (uint64)tmp->nrof * (uint64)tmp->value; |
| tmp = insert_ob_in_ob(tmp, pouch); | | tmp = insert_ob_in_ob(tmp, pouch); |
| esrv_send_item (pl, tmp); | | esrv_send_item (pl, tmp); |
| esrv_send_item (pl, pouch); | | esrv_send_item (pl, pouch); |
| | |
| tmp = get_object(); | | tmp = get_object(); |
| copy_object(&at->clone, tmp); | | copy_object(&at->clone, tmp); |
| tmp->nrof = i/tmp->value; | | tmp->nrof = i/tmp->value; |
| i -= tmp->nrof * tmp->value; | | i -= (uint64)tmp->nrof * (uint64)tmp->value; |
| tmp = insert_ob_in_ob(tmp, pl); | | tmp = insert_ob_in_ob(tmp, pl); |
| esrv_send_item (pl, tmp); | | esrv_send_item (pl, tmp); |
| esrv_send_item (pl, pl); | | esrv_send_item (pl, pl); |