Crossfire Server, Branch 1.12  R12190
shop_inventory.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2007 Crossfire Development Team
00005     Copyright (C) 1992 Frank Tore Johansen
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The authors can be reached via e-mail at crossfire-devel@real-time.com
00022 */
00023 
00027 #include <global.h>
00028 #include <ob_methods.h>
00029 #include <ob_types.h>
00030 #include <sounds.h>
00031 #include <sproto.h>
00032 
00033 static method_ret shop_inventory_type_apply(ob_methods *context, object *lighter, object *applier, int aflags);
00034 
00038 void init_type_shop_inventory(void) {
00039     register_apply(SHOP_INVENTORY, shop_inventory_type_apply);
00040 }
00041 
00045 typedef struct shopinv {
00046     char        *item_sort;     
00047     char        *item_real;     
00048     uint16      type;           
00049     uint32      nrof;           
00050 } shopinv;
00051 
00065 static int shop_sort(const void *a1, const void *a2) {
00066     const shopinv *s1 = (const shopinv *)a1, *s2 = (const shopinv *)a2;
00067 
00068     if (s1->type < s2->type)
00069         return -1;
00070     if (s1->type > s2->type)
00071         return 1;
00072     /* the type is the same (what atoi gets), so do a strcasecmp to sort
00073      * via alphabetical order
00074      */
00075     return strcasecmp(s1->item_sort, s2->item_sort);
00076 }
00077 
00087 static void add_shop_item(object *tmp, shopinv *items, size_t *numitems) {
00088     /* clear unpaid flag so that doesn't come up in query
00089      * string.  We clear nrof so that we can better sort
00090      * the object names.
00091      */
00092     char name[MAX_BUF];
00093 
00094     CLEAR_FLAG(tmp, FLAG_UNPAID);
00095     items[*numitems].nrof = tmp->nrof;
00096     /* Non mergable items have nrof of 0, but count them as one
00097      * so the display is properly.
00098      */
00099     if (tmp->nrof == 0)
00100         items[*numitems].nrof++;
00101     items[*numitems].type = tmp->type;
00102     query_base_name(tmp, 0, name, MAX_BUF);
00103     items[*numitems].item_sort = strdup_local(name);
00104     query_base_name(tmp, 1, name, MAX_BUF);
00105     items[*numitems].item_real = strdup_local(name);
00106     (*numitems)++;
00107 
00108     SET_FLAG(tmp, FLAG_UNPAID);
00109 }
00110 
00125 static method_ret shop_inventory_type_apply(ob_methods *context, object *lighter, object *applier, int aflags) {
00126     size_t i, j, numitems = 0, numallocated = 0;
00127     object *stack;
00128     shopinv *items;
00129 
00130     if (applier->type != PLAYER)
00131         return METHOD_UNHANDLED;
00132 
00133     draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_SHOP, MSG_TYPE_SHOP_LISTING,
00134         "\nThe shop contains:", NULL);
00135 
00136     items = malloc(40*sizeof(shopinv));
00137     numallocated = 40;
00138 
00139     /* Find all the appropriate items */
00140     for (i = 0; i < MAP_WIDTH(applier->map); i++) {
00141         for (j = 0; j < MAP_HEIGHT(applier->map); j++) {
00142             stack = GET_MAP_OB(applier->map, i, j);
00143 
00144             while (stack) {
00145                 if (QUERY_FLAG(stack, FLAG_UNPAID)) {
00146                     if (numitems == numallocated) {
00147                         items = realloc(items, sizeof(shopinv)*(numallocated+10));
00148                         numallocated += 10;
00149                     }
00150                     add_shop_item(stack, items, &numitems);
00151                 }
00152                 stack = stack->above;
00153             }
00154         }
00155     }
00156     if (numitems == 0) {
00157         draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_SHOP, MSG_TYPE_SHOP_LISTING,
00158             "The shop is currently empty.\n", NULL);
00159         free(items);
00160         return METHOD_OK;
00161     }
00162     qsort(items, numitems, sizeof(shopinv), (int (*)(const void *, const void *))shop_sort);
00163 
00164     for (i = 0; i < numitems; i++) {
00165         /* Collapse items of the same name together */
00166         if ((i+1) < numitems && !strcmp(items[i].item_real, items[i+1].item_real)) {
00167             items[i+1].nrof += items[i].nrof;
00168             free(items[i].item_sort);
00169             free(items[i].item_real);
00170         } else {
00171             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_SHOP, MSG_TYPE_SHOP_LISTING,
00172                 "%d %s", "%d %s",
00173                 items[i].nrof ? items[i].nrof : 1,
00174                 items[i].nrof == 1 ? items[i].item_sort : items[i].item_real);
00175             free(items[i].item_sort);
00176             free(items[i].item_real);
00177         }
00178     }
00179     free(items);
00180     return METHOD_OK;
00181 }