Atrinik Server 2.5
server/shop.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00032 static sint64 pay_from_container(object *op, object *pouch, sint64 to_pay);
00033 
00040 sint64 query_cost(object *tmp, object *who, int flag)
00041 {
00042     sint64 val;
00043     double diff;
00044     int number;
00045     int charisma = 11;
00046 
00047     if ((number = tmp->nrof) == 0)
00048     {
00049         number = 1;
00050     }
00051 
00052     /* Money is always identified */
00053     if (tmp->type == MONEY)
00054     {
00055         return (number * tmp->value);
00056     }
00057 
00058     /* Handle identified items */
00059     if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp))
00060     {
00061         if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
00062         {
00063             return 0;
00064         }
00065         else
00066         {
00067             val = tmp->value * number;
00068         }
00069     }
00070     /* This area deals with objects that are not identified, but can be */
00071     else
00072     {
00073         if (tmp->arch != NULL)
00074         {
00075             if (flag == COST_BUY)
00076             {
00077                 LOG(llevBug, "query_cost(): Asking for buy-value of unidentified object %s.\n", query_name(tmp, NULL));
00078                 val = tmp->arch->clone.value * number;
00079             }
00080             /* Trying to sell something, or get true value */
00081             else
00082             {
00083                 /* Selling unidentified gems is *always* stupid */
00084                 if (tmp->type == GEM || tmp->type == JEWEL || tmp->type == NUGGET || tmp->type == PEARL)
00085                 {
00086                     val = number * 3;
00087                 }
00088                 /* Don't want to give anything away */
00089                 else if (tmp->type == POTION)
00090                 {
00091                     val = number * 50;
00092                 }
00093                 else
00094                 {
00095                     val = number * tmp->arch->clone.value;
00096                 }
00097             }
00098         }
00099         else
00100         {
00101             /* No archetype with this object - we generate some dummy values to avoid server break */
00102             LOG(llevBug, "query_cost(): Have object with no archetype: %s\n", query_name(tmp, NULL));
00103 
00104             if (flag == COST_BUY)
00105             {
00106                 LOG(llevBug, "query_cost(): Asking for buy-value of unidentified object without arch.\n");
00107                 val = number * 100;
00108             }
00109             else
00110             {
00111                 val = number * 80;
00112             }
00113         }
00114     }
00115 
00116     /* Wands will count special. The base value is for a wand with one charge */
00117     if (tmp->type == WAND)
00118     {
00119         val += (val * tmp->level) * tmp->stats.food;
00120     }
00121     else if (tmp->type == ROD || tmp->type == HORN || tmp->type == POTION || tmp->type == SCROLL)
00122     {
00123         val += val * tmp->level;
00124     }
00125 
00126     /* We are done if we only want get the real value */
00127     if (flag == COST_TRUE)
00128     {
00129         return val;
00130     }
00131 
00132     /* First, we adjust charisma for players and count skills in */
00133     if (who != NULL && who->type == PLAYER)
00134     {
00135         /* Used for SK_BARGAINING modification */
00136         charisma = who->stats.Cha;
00137 
00138         /* This skill will give us a charisma boost */
00139         if (find_skill(who, SK_BARGAINING))
00140         {
00141             charisma += 4;
00142 
00143             if (charisma > MAX_STAT)
00144             {
00145                 charisma = MAX_STAT;
00146             }
00147         }
00148     }
00149 
00150     /* Now adjust for sell or buy multiplier */
00151     if (flag == COST_BUY)
00152     {
00153         diff = (double) (1.0 - (double) cha_bonus[charisma]);
00154     }
00155     else
00156     {
00157         diff = (double) (0.20 + (double) cha_bonus[charisma]);
00158     }
00159 
00160     val = (val * (long) (1000 * (diff))) / 1000;
00161 
00162     /* We want to give at least 1 copper for items which have any
00163      * value. */
00164     if (val < 1 && tmp->value > 0)
00165     {
00166         val = 1;
00167     }
00168 
00169     return val;
00170 }
00171 
00178 static archetype *find_next_coin(sint64 c, int *cointype)
00179 {
00180     archetype *coin;
00181 
00182     do
00183     {
00184         if (coins[*cointype] == NULL)
00185         {
00186             return NULL;
00187         }
00188 
00189         coin = find_archetype(coins[*cointype]);
00190 
00191         if (coin == NULL)
00192         {
00193             return NULL;
00194         }
00195 
00196         *cointype += 1;
00197     }
00198     while (coin->clone.value > c);
00199 
00200     return coin;
00201 }
00202 
00207 char *cost_string_from_value(sint64 cost)
00208 {
00209     static char buf[MAX_BUF];
00210     archetype *coin, *next_coin;
00211     char *endbuf;
00212     sint64 num;
00213     int cointype = 0;
00214 
00215     coin = find_next_coin(cost, &cointype);
00216 
00217     if (coin == NULL)
00218     {
00219         return "nothing";
00220     }
00221 
00222     num = cost / coin->clone.value;
00223     cost -= num * coin->clone.value;
00224 
00225     if (num == 1)
00226     {
00227         snprintf(buf, sizeof(buf), "1 %s%s", material_real[coin->clone.material_real].name, coin->clone.name);
00228     }
00229     else
00230     {
00231         snprintf(buf, sizeof(buf), "%"FMT64" %s%ss", num, material_real[coin->clone.material_real].name, coin->clone.name);
00232     }
00233 
00234     next_coin = find_next_coin(cost, &cointype);
00235 
00236     if (next_coin == NULL)
00237     {
00238         return buf;
00239     }
00240 
00241     do
00242     {
00243         endbuf = buf + strlen(buf);
00244 
00245         coin = next_coin;
00246         num = cost / coin->clone.value;
00247         cost -= num * coin->clone.value;
00248 
00249         if (cost == 0.0)
00250         {
00251             next_coin = NULL;
00252         }
00253         else
00254         {
00255             next_coin = find_next_coin(cost, &cointype);
00256         }
00257 
00258         if (next_coin)
00259         {
00260             /* There will be at least one more string to add to the list,
00261              * use a comma. */
00262             strcat(endbuf, ", ");
00263             endbuf += 2;
00264         }
00265         else
00266         {
00267             strcat(endbuf, " and ");
00268             endbuf += 5;
00269         }
00270 
00271         if (num == 1)
00272         {
00273             sprintf(endbuf, "1 %s%s", material_real[coin->clone.material_real].name, coin->clone.name);
00274         }
00275         else
00276         {
00277             sprintf(endbuf, "%"FMT64" %s%ss", num, material_real[coin->clone.material_real].name, coin->clone.name);
00278         }
00279 
00280     }
00281     while (next_coin);
00282 
00283     return buf;
00284 }
00285 
00295 char *query_cost_string(object *tmp, object *who, int flag)
00296 {
00297     return cost_string_from_value(query_cost(tmp, who, flag));
00298 }
00299 
00305 sint64 query_money(object *op)
00306 {
00307     object *tmp;
00308     sint64 total = 0;
00309 
00310     if (op->type != PLAYER && op->type != CONTAINER)
00311     {
00312         LOG(llevBug, "query_money(): Called with non player/container.\n");
00313         return 0;
00314     }
00315 
00316     for (tmp = op->inv; tmp; tmp = tmp->below)
00317     {
00318         if (tmp->type == MONEY)
00319         {
00320             total += tmp->nrof * tmp->value;
00321         }
00322         else if (tmp->type == CONTAINER && ((!tmp->race || strstr(tmp->race, "gold")) || QUERY_FLAG(tmp, FLAG_APPLIED)))
00323         {
00324             total += query_money(tmp);
00325         }
00326         else if (tmp->arch->name == shstr_cons.player_info && tmp->name == shstr_cons.BANK_GENERAL)
00327         {
00328             total += tmp->value;
00329         }
00330     }
00331 
00332     return total;
00333 }
00334 
00342 int pay_for_amount(sint64 to_pay, object *pl)
00343 {
00344     object *pouch;
00345 
00346     if (to_pay == 0)
00347     {
00348         return 1;
00349     }
00350 
00351     if (to_pay > query_money(pl))
00352     {
00353         return 0;
00354     }
00355 
00356     to_pay = pay_from_container(NULL, pl, to_pay);
00357 
00358     for (pouch = pl->inv; (pouch != NULL) && (to_pay > 0); pouch = pouch->below)
00359     {
00360         if (pouch->type == CONTAINER && pouch->inv && (QUERY_FLAG(pouch, FLAG_APPLIED) || (!pouch->race || strstr(pouch->race, "gold"))))
00361         {
00362             to_pay = pay_from_container(NULL, pouch, to_pay);
00363         }
00364     }
00365 
00366 #ifndef REAL_WIZ
00367     if (QUERY_FLAG(pl, FLAG_WAS_WIZ))
00368     {
00369         SET_FLAG(op, FLAG_WAS_WIZ);
00370     }
00371 #endif
00372 
00373     fix_player(pl);
00374     return 1;
00375 }
00376 
00385 int pay_for_item(object *op, object *pl)
00386 {
00387     sint64 to_pay = query_cost(op, pl, COST_BUY);
00388     object *pouch;
00389 
00390     if (to_pay == 0.0)
00391     {
00392         return 1;
00393     }
00394 
00395     if (to_pay > query_money(pl))
00396     {
00397         return 0;
00398     }
00399 
00400     to_pay = pay_from_container(op, pl, to_pay);
00401 
00402     for (pouch = pl->inv; (pouch != NULL) && (to_pay > 0); pouch = pouch->below)
00403     {
00404         if (pouch->type == CONTAINER && pouch->inv && (QUERY_FLAG(pouch, FLAG_APPLIED) || (!pouch->race || strstr(pouch->race, "gold"))))
00405         {
00406             to_pay = pay_from_container(op, pouch, to_pay);
00407         }
00408     }
00409 
00410 #ifndef REAL_WIZ
00411     if (QUERY_FLAG(pl, FLAG_WAS_WIZ))
00412     {
00413         SET_FLAG(op, FLAG_WAS_WIZ);
00414     }
00415 #endif
00416 
00417     fix_player(pl);
00418     return 1;
00419 }
00420 
00428 static sint64 pay_from_container(object *op, object *pouch, sint64 to_pay)
00429 {
00430     sint64 remain;
00431     int count, i;
00432     object *tmp, *coin_objs[NUM_COINS], *next, *bank_object = NULL;
00433     archetype *at;
00434     object *who;
00435 
00436     (void) op;
00437 
00438     if (pouch->type != PLAYER && pouch->type != CONTAINER)
00439     {
00440         return to_pay;
00441     }
00442 
00443     remain = to_pay;
00444 
00445     for (i = 0; i < NUM_COINS; i++)
00446     {
00447         coin_objs[i] = NULL;
00448     }
00449 
00450     /* This hunk should remove all the money objects from the player/container */
00451     for (tmp = pouch->inv; tmp; tmp = next)
00452     {
00453         next = tmp->below;
00454 
00455         if (tmp->type == MONEY)
00456         {
00457             for (i = 0; i < NUM_COINS; i++)
00458             {
00459                 if (!strcmp(coins[NUM_COINS - 1 - i], tmp->arch->name) && (tmp->value == tmp->arch->clone.value))
00460                 {
00461                     /* This should not happen, but if it does, just merge
00462                      * the two. */
00463                     if (coin_objs[i] != NULL)
00464                     {
00465                         LOG(llevBug, "pay_from_container(): %s has two money entries of (%s)\n", query_name(pouch, NULL), coins[NUM_COINS - 1 - i]);
00466                         remove_ob(tmp);
00467                         coin_objs[i]->nrof += tmp->nrof;
00468                         esrv_del_item(CONTR(pouch), tmp->count, tmp->env);
00469                     }
00470                     else
00471                     {
00472                         remove_ob(tmp);
00473 
00474                         if (pouch->type == PLAYER)
00475                         {
00476                             esrv_del_item(CONTR(pouch), tmp->count,tmp->env);
00477                         }
00478 
00479                         coin_objs[i] = tmp;
00480                     }
00481 
00482                     break;
00483                 }
00484             }
00485 
00486             if (i == NUM_COINS)
00487             {
00488                 LOG(llevBug, "pay_from_container(): Did not find string match for %s\n", tmp->arch->name);
00489             }
00490         }
00491         else if (tmp->arch->name == shstr_cons.player_info && tmp->name == shstr_cons.BANK_GENERAL)
00492         {
00493             bank_object = tmp;
00494         }
00495     }
00496 
00497     /* Fill in any gaps in the coin_objs array - needed to make change. */
00498     /* Note that the coin_objs array goes from least value to greatest value */
00499     for (i = 0; i < NUM_COINS; i++)
00500     {
00501         if (coin_objs[i] == NULL)
00502         {
00503             at = find_archetype(coins[NUM_COINS - 1 - i]);
00504 
00505             if (at == NULL)
00506             {
00507                 LOG(llevBug, "pay_from_container(): Could not find %s archetype", coins[NUM_COINS - 1 - i]);
00508             }
00509 
00510             coin_objs[i] = get_object();
00511             copy_object(&at->clone, coin_objs[i], 0);
00512             coin_objs[i]->nrof = 0;
00513         }
00514     }
00515 
00516     for (i = 0; i < NUM_COINS; i++)
00517     {
00518         sint64 num_coins;
00519 
00520         if ((sint64) (coin_objs[i]->nrof * coin_objs[i]->value) > remain)
00521         {
00522             num_coins = remain / coin_objs[i]->value;
00523 
00524             if ((num_coins * coin_objs[i]->value) < remain)
00525             {
00526                 num_coins++;
00527             }
00528         }
00529         else
00530         {
00531             num_coins = coin_objs[i]->nrof;
00532         }
00533 
00534         if (num_coins > SINT32_MAX)
00535         {
00536             LOG(llevDebug, "pay_from_container(): Money overflow value->nrof: number of coins > SINT32_MAX (type coin %d)\n", i);
00537             num_coins = SINT32_MAX;
00538         }
00539 
00540         remain -= num_coins * coin_objs[i]->value;
00541         coin_objs[i]->nrof -= (uint32) num_coins;
00542         /* Now start making change.  Start at the coin value
00543          * below the one we just did, and work down to
00544          * the lowest value. */
00545         count = i - 1;
00546 
00547         while (remain < 0 && count >= 0)
00548         {
00549             num_coins = -remain / coin_objs[count]->value;
00550             coin_objs[count]->nrof += (uint32) num_coins;
00551             remain += num_coins * coin_objs[count]->value;
00552             count--;
00553         }
00554     }
00555 
00556     /* If there's still some remain, that means we could try to pay from
00557      * bank. */
00558     if (bank_object && bank_object->value != 0 && remain != 0 && bank_object->value >= remain)
00559     {
00560         bank_object->value -= remain;
00561         remain = 0;
00562     }
00563 
00564     for (i = 0; i < NUM_COINS; i++)
00565     {
00566         if (coin_objs[i]->nrof)
00567         {
00568             tmp = insert_ob_in_ob(coin_objs[i], pouch);
00569 
00570             for (who = pouch; who && who->type != PLAYER && who->env != NULL; who = who->env)
00571             {
00572             }
00573 
00574             esrv_send_item(who, tmp);
00575             esrv_send_item (who, pouch);
00576             esrv_update_item(UPD_WEIGHT, who, pouch);
00577 
00578             if (pouch->type != PLAYER)
00579             {
00580                 esrv_send_item(who, who);
00581                 esrv_update_item(UPD_WEIGHT, who, who);
00582             }
00583         }
00584     }
00585 
00586     return remain;
00587 }
00588 
00596 int get_payment(object *pl, object *op)
00597 {
00598     char buf[MAX_BUF];
00599     int ret = 1;
00600 
00601     if (op != NULL && op->inv)
00602     {
00603         ret = get_payment(pl, op->inv);
00604     }
00605 
00606     if (!ret)
00607     {
00608         return 0;
00609     }
00610 
00611     if (op != NULL && op->below)
00612     {
00613         ret = get_payment(pl, op->below);
00614     }
00615 
00616     if (!ret)
00617     {
00618         return 0;
00619     }
00620 
00621     if (op != NULL && QUERY_FLAG(op, FLAG_UNPAID))
00622     {
00623         strncpy(buf, query_cost_string(op, pl, COST_BUY), sizeof(buf));
00624 
00625         if (!pay_for_item(op, pl))
00626         {
00627             sint64 i = query_cost(op, pl, COST_BUY) - query_money(pl);
00628 
00629             CLEAR_FLAG(op, FLAG_UNPAID);
00630             new_draw_info_format(0, COLOR_WHITE, pl, "You lack %s to buy %s.", cost_string_from_value(i), query_name(op, NULL));
00631             SET_FLAG(op, FLAG_UNPAID);
00632             return 0;
00633         }
00634         else
00635         {
00636             object *tmp, *c_cont = op->env;
00637             tag_t c = op->count;
00638 
00639             CLEAR_FLAG(op, FLAG_UNPAID);
00640             CLEAR_FLAG(op, FLAG_STARTEQUIP);
00641 
00642             if (pl->type == PLAYER)
00643             {
00644                 new_draw_info_format(0, COLOR_WHITE, pl, "You paid %s for %s.", buf, query_name(op, NULL));
00645             }
00646 
00647             tmp = merge_ob(op, NULL);
00648 
00649             if (pl->type == PLAYER)
00650             {
00651                 /* It was merged */
00652                 if (tmp)
00653                 {
00654                     esrv_del_item(CONTR(pl), c, c_cont);
00655                     op = tmp;
00656                 }
00657 
00658                 esrv_send_item(pl, op);
00659             }
00660         }
00661     }
00662 
00663     return 1;
00664 }
00665 
00672 void sell_item(object *op, object *pl, sint64 value)
00673 {
00674     sint64 i;
00675 
00676     if (pl == NULL || pl->type != PLAYER)
00677     {
00678         LOG(llevDebug, "sell_item(): Object other than player tried to sell something.\n");
00679         return;
00680     }
00681 
00682     if (op == NULL)
00683     {
00684         i = value;
00685     }
00686     else
00687     {
00688         i = query_cost(op, pl, COST_SELL);
00689     }
00690 
00691     if (op && op->custom_name)
00692     {
00693         FREE_AND_CLEAR_HASH(op->custom_name);
00694     }
00695 
00696     if (!i)
00697     {
00698         if (op)
00699         {
00700             new_draw_info_format(0, COLOR_WHITE, pl, "We're not interested in %s.", query_name(op, NULL));
00701         }
00702     }
00703 
00704     i = insert_coins(pl, i);
00705 
00706     if (!op)
00707     {
00708         return;
00709     }
00710 
00711     if (i != 0)
00712     {
00713         LOG(llevBug, "Warning - payment not zero: %"FMT64"\n", i);
00714     }
00715 
00716     new_draw_info_format(0, COLOR_WHITE, pl, "You receive %s for %s.", query_cost_string(op, pl, 1), query_name(op, NULL));
00717     SET_FLAG(op, FLAG_UNPAID);
00718 
00719     /* Identify the item. Makes any unidentified item sold to unique shop appear identified. */
00720     identify(op);
00721 }
00722 
00728 int get_money_from_string(const char *text, struct _money_block *money)
00729 {
00730     int pos = 0;
00731     const char *word;
00732 
00733     memset(money, 0, sizeof(struct _money_block));
00734 
00735     /* Kill all whitespace */
00736     while (*text !='\0' && (isspace(*text) || !isprint(*text)))
00737     {
00738         text++;
00739     }
00740 
00741     /* Easy, special case: all money */
00742     if (!strncasecmp(text, "all", 3))
00743     {
00744         money->mode = MONEYSTRING_ALL;
00745         return money->mode;
00746     }
00747 
00748     money->mode = MONEYSTRING_NOTHING;
00749 
00750     while ((word = get_word_from_string(text, &pos)))
00751     {
00752         int i = 0, flag = *word;
00753 
00754         while (*(word + i) != '\0')
00755         {
00756             if (*(word + i) < '0' || *(word + i) > '9')
00757             {
00758                 flag = 0;
00759             }
00760 
00761             i++;
00762         }
00763 
00764         /* If still set, we have a valid number in the word string */
00765         if (flag)
00766         {
00767             int value = atoi(word);
00768 
00769             /* A valid number - now lets look we have a valid money keyword */
00770             if (value > 0 && value < 1000000)
00771             {
00772                 if ((word = get_word_from_string(text, &pos)) && *word != '\0')
00773                 {
00774                     size_t len = strlen(word);
00775 
00776                     if (!strncasecmp("mithril", word, len))
00777                     {
00778                         money->mode = MONEYSTRING_AMOUNT;
00779                         money->mithril += value;
00780                     }
00781                     else if (!strncasecmp("gold", word, len))
00782                     {
00783                         money->mode = MONEYSTRING_AMOUNT;
00784                         money->gold += value;
00785                     }
00786                     else if (!strncasecmp("silver", word, len))
00787                     {
00788                         money->mode = MONEYSTRING_AMOUNT;
00789                         money->silver += value;
00790                     }
00791                     else if (!strncasecmp("copper", word, len))
00792                     {
00793                         money->mode = MONEYSTRING_AMOUNT;
00794                         money->copper += value;
00795                     }
00796                 }
00797             }
00798         }
00799     }
00800 
00801     return money->mode;
00802 }
00803 
00809 int query_money_type(object *op, int value)
00810 {
00811     object *tmp;
00812     sint64 total = 0;
00813 
00814     for (tmp = op->inv; tmp; tmp = tmp->below)
00815     {
00816         if (tmp->type == MONEY && tmp->value == value)
00817         {
00818             total += tmp->nrof;
00819         }
00820         else if (tmp->type == CONTAINER && !tmp->slaying && ((!tmp->race || strstr(tmp->race, "gold"))))
00821         {
00822             total += query_money_type(tmp, value);
00823         }
00824 
00825         if (total >= (sint64) value)
00826         {
00827             break;
00828         }
00829     }
00830 
00831     return (int) total;
00832 }
00833 
00841 sint64 remove_money_type(object *who, object *op, sint64 value, sint64 amount)
00842 {
00843     object *tmp, *tmp2;
00844 
00845     for (tmp = op->inv; tmp; tmp = tmp2)
00846     {
00847         tmp2 = tmp->below;
00848 
00849         if (!amount && value != -1)
00850         {
00851             return amount;
00852         }
00853 
00854         if (tmp->type == MONEY && (tmp->value == value || value == -1))
00855         {
00856             if ((sint64) tmp->nrof <= amount || value == -1)
00857             {
00858                 object *env = tmp->env;
00859 
00860                 if (value == -1)
00861                 {
00862                     amount += (tmp->nrof * tmp->value);
00863                 }
00864                 else
00865                 {
00866                     amount -= tmp->nrof;
00867                 }
00868 
00869                 remove_ob(tmp);
00870 
00871                 if (op->type == PLAYER)
00872                 {
00873                     esrv_del_item(CONTR(op), tmp->count, NULL);
00874                 }
00875                 else
00876                 {
00877                     esrv_del_item(NULL, tmp->count, env);
00878                 }
00879             }
00880             else
00881             {
00882                 tmp->nrof -= (uint32) amount;
00883                 amount = 0;
00884 
00885                 esrv_send_item(who, tmp);
00886                 esrv_send_item(who, op);
00887                 esrv_update_item(UPD_WEIGHT, who, op);
00888 
00889                 if (op->type != PLAYER)
00890                 {
00891                     esrv_send_item(who, who);
00892                     esrv_update_item(UPD_WEIGHT, who, who);
00893                 }
00894             }
00895         }
00896         else if (tmp->type == CONTAINER && !tmp->slaying && ((!tmp->race || strstr(tmp->race, "gold"))))
00897         {
00898             amount = remove_money_type(who, tmp, value, amount);
00899         }
00900     }
00901 
00902     return amount;
00903 }
00904 
00910 void insert_money_in_player(object *pl, object *money, uint32 nrof)
00911 {
00912     object *tmp = get_object();
00913     copy_object(money, tmp, 0);
00914     tmp->nrof = nrof;
00915     tmp = insert_ob_in_ob(tmp, pl);
00916     esrv_send_item(pl, tmp);
00917     esrv_send_item(pl, pl);
00918     esrv_update_item(UPD_WEIGHT, pl, pl);
00919 }
00920 
00925 object *bank_get_info(object *op)
00926 {
00927     object *tmp;
00928 
00929     for (tmp = op->inv; tmp; tmp = tmp->below)
00930     {
00931         if (tmp->arch->name == shstr_cons.player_info && tmp->name == shstr_cons.BANK_GENERAL)
00932         {
00933             return tmp;
00934         }
00935     }
00936 
00937     return NULL;
00938 }
00939 
00944 object *bank_create_info(object *op)
00945 {
00946     object *bank = get_archetype(shstr_cons.player_info);
00947 
00948     FREE_AND_COPY_HASH(bank->name, shstr_cons.BANK_GENERAL);
00949     insert_ob_in_ob(bank, op);
00950 
00951     return bank;
00952 }
00953 
00959 object *bank_get_create_info(object *op)
00960 {
00961     object *bank = bank_get_info(op);
00962 
00963     if (!bank)
00964     {
00965         bank = bank_create_info(op);
00966     }
00967 
00968     return bank;
00969 }
00970 
00975 sint64 bank_get_balance(object *op)
00976 {
00977     object *bank = bank_get_info(op);
00978 
00979     if (!bank)
00980     {
00981         return 0;
00982     }
00983 
00984     return bank->value;
00985 }
00986 
00993 int bank_deposit(object *op, const char *text, sint64 *value)
00994 {
00995     int pos = 0;
00996     _money_block money;
00997     object *bank;
00998 
00999     get_word_from_string(text, &pos);
01000     get_money_from_string(text + pos, &money);
01001     *value = 0;
01002 
01003     if (!money.mode)
01004     {
01005         return BANK_SYNTAX_ERROR;
01006     }
01007     else if (money.mode == MONEYSTRING_ALL)
01008     {
01009         bank = bank_get_create_info(op);
01010         *value = remove_money_type(op, op, -1, 0);
01011         bank->value += *value;
01012         fix_player(op);
01013     }
01014     else
01015     {
01016         if (money.mithril)
01017         {
01018             if (query_money_type(op, coins_arch[0]->clone.value) < money.mithril)
01019             {
01020                 return BANK_DEPOSIT_MITHRIL;
01021             }
01022         }
01023 
01024         if (money.gold)
01025         {
01026             if (query_money_type(op, coins_arch[1]->clone.value) < money.gold)
01027             {
01028                 return BANK_DEPOSIT_GOLD;
01029             }
01030         }
01031 
01032         if (money.silver)
01033         {
01034             if (query_money_type(op, coins_arch[2]->clone.value) < money.silver)
01035             {
01036                 return BANK_DEPOSIT_SILVER;
01037             }
01038         }
01039 
01040         if (money.copper)
01041         {
01042             if (query_money_type(op, coins_arch[3]->clone.value) < money.copper)
01043             {
01044                 return BANK_DEPOSIT_COPPER;
01045             }
01046         }
01047 
01048         if (money.mithril)
01049         {
01050             remove_money_type(op, op, coins_arch[0]->clone.value, money.mithril);
01051         }
01052 
01053         if (money.gold)
01054         {
01055             remove_money_type(op, op, coins_arch[1]->clone.value, money.gold);
01056         }
01057 
01058         if (money.silver)
01059         {
01060             remove_money_type(op, op, coins_arch[2]->clone.value, money.silver);
01061         }
01062 
01063         if (money.copper)
01064         {
01065             remove_money_type(op, op, coins_arch[3]->clone.value, money.copper);
01066         }
01067 
01068         bank = bank_get_create_info(op);
01069         *value = money.mithril * coins_arch[0]->clone.value + money.gold * coins_arch[1]->clone.value + money.silver * coins_arch[2]->clone.value + money.copper * coins_arch[3]->clone.value;
01070         bank->value += *value;
01071         fix_player(op);
01072     }
01073 
01074     return BANK_SUCCESS;
01075 }
01076 
01084 int bank_withdraw(object *op, const char *text, sint64 *value)
01085 {
01086     int pos = 0;
01087     sint64 big_value;
01088     _money_block money;
01089     object *bank;
01090 
01091     get_word_from_string(text, &pos);
01092     get_money_from_string(text + pos, &money);
01093 
01094     bank = bank_get_info(op);
01095     *value = 0;
01096 
01097     if (!bank || !bank->value)
01098     {
01099         return BANK_WITHDRAW_MISSING;
01100     }
01101 
01102     if (!money.mode)
01103     {
01104         return BANK_SYNTAX_ERROR;
01105     }
01106     else if (money.mode == MONEYSTRING_ALL)
01107     {
01108         *value = bank->value;
01109         sell_item(NULL, op, bank->value);
01110         bank->value = 0;
01111         fix_player(op);
01112     }
01113     else
01114     {
01115         /* Just to set a border. */
01116         if (money.mithril > 100000 || money.gold > 100000 || money.silver > 1000000 || money.copper > 1000000)
01117         {
01118             return BANK_WITHDRAW_HIGH;
01119         }
01120 
01121         big_value = money.mithril * coins_arch[0]->clone.value + money.gold * coins_arch[1]->clone.value + money.silver * coins_arch[2]->clone.value + money.copper * coins_arch[3]->clone.value;
01122 
01123         if (big_value > bank->value)
01124         {
01125             return BANK_WITHDRAW_MISSING;
01126         }
01127 
01128         if (!player_can_carry(op, money.mithril * coins_arch[0]->clone.weight + money.gold * coins_arch[1]->clone.weight + money.silver * coins_arch[2]->clone.weight + money.copper * coins_arch[3]->clone.weight))
01129         {
01130             return BANK_WITHDRAW_OVERWEIGHT;
01131         }
01132 
01133         if (money.mithril)
01134         {
01135             insert_money_in_player(op, &coins_arch[0]->clone, money.mithril);
01136         }
01137 
01138         if (money.gold)
01139         {
01140             insert_money_in_player(op, &coins_arch[1]->clone, money.gold);
01141         }
01142 
01143         if (money.silver)
01144         {
01145             insert_money_in_player(op, &coins_arch[2]->clone, money.silver);
01146         }
01147 
01148         if (money.copper)
01149         {
01150             insert_money_in_player(op, &coins_arch[3]->clone, money.copper);
01151         }
01152 
01153         *value = big_value;
01154         bank->value -= big_value;
01155         fix_player(op);
01156     }
01157 
01158     return BANK_SUCCESS;
01159 }
01160 
01166 sint64 insert_coins(object *pl, sint64 value)
01167 {
01168     int count;
01169     object *tmp, *pouch;
01170     archetype *at;
01171 
01172     for (count = 0; coins[count]; count++)
01173     {
01174         at = find_archetype(coins[count]);
01175 
01176         if (at == NULL)
01177         {
01178             LOG(llevBug, "Could not find %s archetype", coins[count]);
01179         }
01180         else if ((value / at->clone.value) > 0)
01181         {
01182             for (pouch = pl->inv; pouch; pouch = pouch->below)
01183             {
01184                 if (pouch->type == CONTAINER && QUERY_FLAG(pouch, FLAG_APPLIED) && pouch->race && strstr(pouch->race, "gold"))
01185                 {
01186                     int w = (int) ((float) at->clone.weight * pouch->weapon_speed);
01187                     uint32 n = (uint32) (value / at->clone.value);
01188 
01189                     /* Prevent FPE */
01190                     if (w == 0)
01191                     {
01192                         w = 1;
01193                     }
01194 
01195                     if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= (sint32) pouch->weight_limit))
01196                     {
01197                         if (pouch->weight_limit && ((sint32)pouch->weight_limit-pouch->carrying) / w < (sint32) n)
01198                         {
01199                             n = (pouch->weight_limit-pouch->carrying) / w;
01200                         }
01201 
01202                         tmp = get_object();
01203                         copy_object(&at->clone, tmp, 0);
01204                         tmp->nrof = n;
01205                         value -= tmp->nrof * tmp->value;
01206                         tmp = insert_ob_in_ob(tmp, pouch);
01207                         esrv_send_item(pl, tmp);
01208                         esrv_send_item(pl, pouch);
01209                         esrv_update_item(UPD_WEIGHT, pl, pouch);
01210                         esrv_send_item(pl, pl);
01211                         esrv_update_item(UPD_WEIGHT, pl, pl);
01212                     }
01213                 }
01214             }
01215 
01216             if (value / at->clone.value > 0)
01217             {
01218                 tmp = get_object();
01219                 copy_object(&at->clone, tmp, 0);
01220                 tmp->nrof = (uint32) (value / tmp->value);
01221                 value -= tmp->nrof * tmp->value;
01222                 tmp = insert_ob_in_ob(tmp, pl);
01223                 esrv_send_item(pl, tmp);
01224                 esrv_send_item(pl, pl);
01225                 esrv_update_item(UPD_WEIGHT, pl, pl);
01226             }
01227         }
01228     }
01229 
01230     return value;
01231 }