Crossfire Server, Branch 1.12  R12190
converter.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2007 Mark Wedel & 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 /*
00034  * convert_item() returns 1 if anything was converted, 0 if the item was not
00035  * what the converter wants, -1 if the converter is broken.
00036  */
00037 #define CONV_FROM(xyz)  xyz->slaying
00038 #define CONV_TO(xyz)    xyz->other_arch
00039 #define CONV_NR(xyz)    (unsigned char)xyz->stats.sp
00040 #define CONV_NEED(xyz)  (unsigned long)xyz->stats.food
00041 
00042 static int convert_item(object *item, object *converter);
00043 
00044 static method_ret converter_type_move_on(ob_methods *context, object *trap, object *victim, object *originator);
00045 
00049 void init_type_converter(void) {
00050     register_move_on(CONVERTER, converter_type_move_on);
00051 }
00052 
00062 static int convert_item(object *item, object *converter) {
00063     int nr = 0;
00064     uint32 price_in;
00065 
00066     /* We make some assumptions - we assume if it takes money as it type,
00067      * it wants some amount.  We don't make change (ie, if something costs
00068      * 3 gp and player drops a platinum, tough luck)
00069      */
00070     if (!strcmp(CONV_FROM(converter), "money")) {
00071         int cost;
00072 
00073         if (item->type != MONEY)
00074             return 0;
00075 
00076         nr = (item->nrof*item->value)/CONV_NEED(converter);
00077         if (!nr)
00078             return 0;
00079 
00080         cost = nr*CONV_NEED(converter)/item->value;
00081         /* take into account rounding errors */
00082         if (nr*CONV_NEED(converter)%item->value)
00083             cost++;
00084         decrease_ob_nr(item, cost);
00085 
00086         price_in = cost*item->value;
00087     } else {
00088         if (item->type == PLAYER
00089         || CONV_FROM(converter) != item->arch->name
00090         || (CONV_NEED(converter) && CONV_NEED(converter) > item->nrof))
00091             return 0;
00092 
00093         /* silently burn unpaid items (only if they match what we want) */
00094         if (QUERY_FLAG(item, FLAG_UNPAID)) {
00095             remove_ob(item);
00096             free_object(item);
00097             item = create_archetype("burnout");
00098             if (item != NULL)
00099                 insert_ob_in_map_at(item, converter->map, converter, 0, converter->x, converter->y);
00100             return 1;
00101         }
00102 
00103         if (CONV_NEED(converter)) {
00104             nr = item->nrof/CONV_NEED(converter);
00105             decrease_ob_nr(item, nr*CONV_NEED(converter));
00106             price_in = nr*CONV_NEED(converter)*item->value;
00107         } else {
00108             price_in = item->value;
00109             remove_ob(item);
00110             free_object(item);
00111         }
00112     }
00113 
00114     if (converter->inv != NULL) {
00115         object *ob;
00116         int i;
00117         object *ob_to_copy;
00118 
00119         /* select random object from inventory to copy */
00120         ob_to_copy = converter->inv;
00121         for (ob = converter->inv->below, i = 1; ob != NULL; ob = ob->below, i++) {
00122             if (rndm(0, i) == 0)
00123                 ob_to_copy = ob;
00124         }
00125         item = object_create_clone(ob_to_copy);
00126         CLEAR_FLAG(item, FLAG_IS_A_TEMPLATE);
00127         unflag_inv(item, FLAG_IS_A_TEMPLATE);
00128     } else {
00129         if (converter->other_arch == NULL) {
00130             LOG(llevError, "move_creator: Converter doesn't have other arch set: %s (%s, %d, %d)\n", converter->name ? converter->name : "(null)", converter->map->path, converter->x, converter->y);
00131             return -1;
00132         }
00133         item = object_create_arch(converter->other_arch);
00134         fix_generated_item(item, converter, 0, 0, GT_MINIMAL);
00135     }
00136 
00137     if (CONV_NR(converter))
00138         item->nrof = CONV_NR(converter);
00139     if (nr)
00140         item->nrof *= nr;
00141     if (is_in_shop(converter))
00142         SET_FLAG(item, FLAG_UNPAID);
00143     else if (price_in < item->nrof*item->value && settings.allow_broken_converters == FALSE) {
00144         LOG(llevError, "Broken converter %s at %s (%d, %d) in value %d, out value %d for %s\n", converter->name, converter->map->path, converter->x, converter->y, price_in, item->nrof*item->value, item->name);
00145         free_object(item);
00146         return -1;
00147     }
00148     insert_ob_in_map_at(item, converter->map, converter, 0, converter->x, converter->y);
00149     return 1;
00150 }
00151 
00160 static method_ret converter_type_move_on(ob_methods *context, object *trap, object *victim, object *originator) {
00161     if (common_pre_ob_move_on(trap, victim, originator) == METHOD_ERROR)
00162         return METHOD_OK;
00163     if (convert_item(victim, trap) < 0) {
00164         object *op;
00165         char name[MAX_BUF];
00166 
00167         query_name(trap, name, MAX_BUF);
00168         draw_ext_info_format(NDI_UNIQUE, 0, originator, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00169             "The %s seems to be broken!", "The %s seems to be broken!",
00170             name);
00171 
00172         op = create_archetype("burnout");
00173         if (op != NULL) {
00174             op->x = trap->x;
00175             op->y = trap->y;
00176             insert_ob_in_map(op, trap->map, trap, 0);
00177         }
00178     }
00179     common_post_ob_move_on(trap, victim, originator);
00180     return METHOD_OK;
00181 }