Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_object_c = 00003 * "$Id: object.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00034 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects. 00035 sub/add_weight will transcend the environment updating the carrying 00036 variable. */ 00037 00038 #include <stdlib.h> 00039 #include <string.h> 00040 #include <global.h> 00041 #ifndef WIN32 /* ---win32 exclude headers */ 00042 #include <stdio.h> 00043 #include <sys/types.h> 00044 #include <sys/uio.h> 00045 #endif /* win32 */ 00046 #include <object.h> 00047 #include <skills.h> 00048 #include <loader.h> 00049 #include <sproto.h> 00050 #include "stringbuffer.h" 00051 00052 static int compare_ob_value_lists_one(const object *, const object *); 00053 static int compare_ob_value_lists(const object *, const object *); 00054 static void expand_objects(void); 00055 static void permute(int *, int, int); 00056 static int set_ob_key_value_s(object *, const char *, const char *, int); 00057 static void increase_ob_nr(object *op, uint32 i); 00058 00059 #ifdef MEMORY_DEBUG 00060 int nroffreeobjects = 0; 00061 int nrofallocobjects = 0; 00062 #undef OBJ_EXPAND 00063 #define OBJ_EXPAND 1 00064 #else 00065 object objarray[STARTMAX]; 00066 int nroffreeobjects = STARTMAX; 00067 int nrofallocobjects = STARTMAX; 00068 #endif 00069 00070 object *objects; 00071 object *free_objects; 00072 object *active_objects; 00075 short freearr_x[SIZEOFFREE] = { 00076 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1, 00077 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1 00078 }; 00079 00081 short freearr_y[SIZEOFFREE] = { 00082 0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, 00083 -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3 00084 }; 00085 00087 int maxfree[SIZEOFFREE] = { 00088 0, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 00089 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 00090 }; 00091 00093 int freedir[SIZEOFFREE] = { 00094 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 00095 1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8 00096 }; 00097 00108 static int compare_ob_value_lists_one(const object *wants, const object *has) { 00109 key_value *wants_field; 00110 00111 /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both 00112 * objects with lists are rare, and lists stay short. If not, use a 00113 * different structure or at least keep the lists sorted... 00114 */ 00115 00116 /* For each field in wants, */ 00117 for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) { 00118 key_value *has_field; 00119 00120 /* Look for a field in has with the same key. */ 00121 has_field = get_ob_key_link(has, wants_field->key); 00122 00123 if (has_field == NULL) { 00124 /* No field with that name. */ 00125 return FALSE; 00126 } 00127 00128 /* Found the matching field. */ 00129 if (has_field->value != wants_field->value) { 00130 /* Values don't match, so this half of the comparison is false. */ 00131 return FALSE; 00132 } 00133 00134 /* If we get here, we found a match. Now for the next field in wants. */ 00135 } 00136 00137 /* If we get here, every field in wants has a matching field in has. */ 00138 return TRUE; 00139 } 00140 00149 static int compare_ob_value_lists(const object *ob1, const object *ob2) { 00150 /* However, there may be fields in has which aren't partnered in wants, 00151 * so we need to run the comparison *twice*. :( 00152 */ 00153 return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1); 00154 } 00155 00178 int can_merge(object *ob1, object *ob2) { 00179 00180 /* A couple quicksanity checks */ 00181 if ((ob1 == ob2) || (ob1->type != ob2->type)) 00182 return 0; 00183 00184 if (ob1->speed != ob2->speed) 00185 return 0; 00186 /* Note sure why the following is the case - either the object has to 00187 * be animated or have a very low speed. Is this an attempted monster 00188 * check? 00189 */ 00190 /*TODO is this check really needed?*/ 00191 if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED) 00192 return 0; 00193 00194 /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that 00195 * value could not be stored in a sint32 (which unfortunately sometimes is 00196 * used to store nrof). 00197 */ 00198 if (ob1->nrof+ob2->nrof >= 1UL<<31) 00199 return 0; 00200 00201 /* This is really a spellbook check - really, we should 00202 * check all objects in the inventory. 00203 */ 00204 /*TODO is this check really needed?*/ 00205 if (ob1->inv || ob2->inv) { 00206 /* if one object has inventory but the other doesn't, not equiv */ 00207 if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv)) 00208 return 0; 00209 00210 /* Now check to see if the two inventory objects could merge */ 00211 if (!can_merge(ob1->inv, ob2->inv)) 00212 return 0; 00213 00214 /* inventory ok - still need to check rest of this object to see 00215 * if it is valid. 00216 */ 00217 } 00218 00219 /* If the objects have been identified, set the BEEN_APPLIED flag. 00220 * This is to the comparison of the flags below will be OK. We 00221 * just can't ignore the been applied or identified flags, as they 00222 * are not equal - just if it has been identified, the been_applied 00223 * flags lose any meaning. 00224 */ 00225 00226 /*TODO is this hack on BEEN_APPLIED really needed? */ 00227 if (QUERY_FLAG(ob1, FLAG_IDENTIFIED)) 00228 SET_FLAG(ob1, FLAG_BEEN_APPLIED); 00229 00230 if (QUERY_FLAG(ob2, FLAG_IDENTIFIED)) 00231 SET_FLAG(ob2, FLAG_BEEN_APPLIED); 00232 00233 00234 /* Note: FLAG_INV_LOCKED is ignored for merging purposes */ 00235 if ((ob1->arch != ob2->arch) 00236 || (ob1->flags[0] != ob2->flags[0]) 00237 || (ob1->flags[1] != ob2->flags[1]) 00238 || (ob1->flags[2] != ob2->flags[2]) 00239 || ((ob1->flags[3]&~0x4) != (ob2->flags[3]&~0x4)) /* ignore CLIENT_SENT */ 00240 || (ob1->name != ob2->name) 00241 || (ob1->title != ob2->title) 00242 || (ob1->msg != ob2->msg) 00243 || (ob1->weight != ob2->weight) 00244 || (ob1->item_power != ob2->item_power) 00245 || (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist)) != 0) 00246 || (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats)) != 0) 00247 || (ob1->attacktype != ob2->attacktype) 00248 || (ob1->magic != ob2->magic) 00249 || (ob1->slaying != ob2->slaying) 00250 || (ob1->skill != ob2->skill) 00251 || (ob1->value != ob2->value) 00252 || (ob1->animation_id != ob2->animation_id) 00253 || (ob1->client_type != ob2->client_type) 00254 || (ob1->materialname != ob2->materialname) 00255 || (ob1->lore != ob2->lore) 00256 || (ob1->subtype != ob2->subtype) 00257 || (ob1->move_type != ob2->move_type) 00258 || (ob1->move_block != ob2->move_block) 00259 || (ob1->move_allow != ob2->move_allow) 00260 || (ob1->move_on != ob2->move_on) 00261 || (ob1->move_off != ob2->move_off) 00262 || (ob1->move_slow != ob2->move_slow) 00263 || (ob1->move_slow_penalty != ob2->move_slow_penalty) 00264 || (ob1->map_layer != ob2->map_layer)) 00265 return 0; 00266 00267 /* Don't merge objects that are applied. With the new 'body' code, 00268 * it is possible for most any character to have more than one of 00269 * some items equipped, and we don't want those to merge. 00270 */ 00271 if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED)) 00272 return 0; 00273 00274 if (ob1->key_values != NULL || ob2->key_values != NULL) { 00275 /* At least one of these has key_values. */ 00276 if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) { 00277 /* One has fields, but the other one doesn't. */ 00278 return 0; 00279 } else { 00280 return compare_ob_value_lists(ob1, ob2); 00281 } 00282 } 00283 00284 /*TODO should this really be limited to scrolls?*/ 00285 switch (ob1->type) { 00286 case SCROLL: 00287 if (ob1->level != ob2->level) 00288 return 0; 00289 break; 00290 00291 } 00292 00293 /* Don't merge items with differing custom names. */ 00294 if (ob1->custom_name != ob2->custom_name) 00295 return 0; 00296 00297 /* Everything passes, must be OK. */ 00298 return 1; 00299 } 00300 00316 /* TODO should check call this this are made a place where we really need reevaluaton of whole tree */ 00317 signed long sum_weight(object *op) { 00318 signed long sum; 00319 object *inv; 00320 00321 for (sum = 0, inv = op->inv; inv != NULL; inv = inv->below) { 00322 if (inv->inv) 00323 sum_weight(inv); 00324 sum += inv->carrying+inv->weight*(inv->nrof ? inv->nrof : 1); 00325 } 00326 if (op->type == CONTAINER && op->stats.Str) 00327 sum = (sum*(100-op->stats.Str))/100; 00328 op->carrying = sum; 00329 return sum; 00330 } 00331 00339 object *object_get_env_recursive(object *op) { 00340 while (op->env != NULL) 00341 op = op->env; 00342 return op; 00343 } 00344 00356 object *get_player_container(object *op) { 00357 for (; op != NULL && op->type != PLAYER; op = op->env) 00358 /*TODO this is patching the structure on the flight as side effect. Shoudln't be needed in clean code */ 00359 if (op->env == op) 00360 op->env = NULL; 00361 return op; 00362 } 00363 00372 void dump_object(object *op, StringBuffer *sb) { 00373 if (op == NULL) { 00374 stringbuffer_append_string(sb, "[NULL pointer]"); 00375 return; 00376 } 00377 00378 /* object *tmp;*/ 00379 00380 if (op->arch != NULL) { 00381 stringbuffer_append_string(sb, "arch "); 00382 stringbuffer_append_string(sb, op->arch->name ? op->arch->name : "(null)"); 00383 stringbuffer_append_string(sb, "\n"); 00384 00385 get_ob_diff(sb, op, &empty_archetype->clone); 00386 if (op->more) { 00387 stringbuffer_append_printf(sb, "more %u\n", op->more->count); 00388 } 00389 if (op->head) { 00390 stringbuffer_append_printf(sb, "head %u\n", op->head->count); 00391 } 00392 if (op->env) { 00393 stringbuffer_append_printf(sb, "env %u\n", op->env->count); 00394 } 00395 if (op->inv) { 00396 stringbuffer_append_printf(sb, "inv %u\n", op->inv->count); 00397 } 00398 if (op->owner) { 00399 stringbuffer_append_printf(sb, "owner %u\n", op->owner->count); 00400 } 00401 stringbuffer_append_string(sb, "end\n"); 00402 } else { 00403 stringbuffer_append_string(sb, "Object "); 00404 stringbuffer_append_string(sb, op->name == NULL ? "(null)" : op->name); 00405 stringbuffer_append_string(sb, "\nend\n"); 00406 } 00407 } 00408 00416 void dump_all_objects(void) { 00417 object *op; 00418 00419 for (op = objects; op != NULL; op = op->next) { 00420 StringBuffer *sb; 00421 char *diff; 00422 00423 sb = stringbuffer_new(); 00424 dump_object(op, sb); 00425 diff = stringbuffer_finish(sb); 00426 LOG(llevDebug, "Object %d\n:%s\n", op->count, diff); 00427 free(diff); 00428 } 00429 } 00430 00439 object *find_object(tag_t i) { 00440 object *op; 00441 00442 for (op = objects; op != NULL; op = op->next) 00443 if (op->count == i) 00444 break; 00445 return op; 00446 } 00447 00459 object *find_object_name(const char *str) { 00460 const char *name = add_string(str); 00461 object *op; 00462 00463 for (op = objects; op != NULL; op = op->next) 00464 if (op->name == name) 00465 break; 00466 free_string(name); 00467 return op; 00468 } 00469 00479 void free_all_object_data(void) { 00480 #ifdef MEMORY_DEBUG 00481 object *op, *next; 00482 00483 for (op = free_objects; op != NULL; ) { 00484 next = op->next; 00485 free(op); 00486 nrofallocobjects--; 00487 nroffreeobjects--; 00488 op = next; 00489 } 00490 00491 for (op = objects; op != NULL; ) { 00492 next = op->next; 00493 if (!QUERY_FLAG(op, FLAG_FREED)) { 00494 LOG(llevDebug, "non freed object: %s\n", op->name); 00495 } 00496 op = next; 00497 } 00498 #endif 00499 00500 LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX); 00501 } 00502 00524 object *get_owner(object *op) { 00525 if (op->owner == NULL) 00526 return NULL; 00527 00528 if (!QUERY_FLAG(op->owner, FLAG_FREED) 00529 && !QUERY_FLAG(op->owner, FLAG_REMOVED) 00530 && op->owner->count == op->ownercount) 00531 return op->owner; 00532 LOG(llevError, "I had to clean an owner when in get_owner, this isn't my job.\n"); 00533 op->owner = NULL; 00534 op->ownercount = 0; 00535 return NULL; 00536 } 00537 00544 void clear_owner(object *op) { 00545 if (!op) 00546 return; 00547 00548 op->owner = NULL; 00549 op->ownercount = 0; 00550 } 00551 00564 void set_owner(object *op, object *owner) { 00565 if (op == NULL) 00566 return; 00567 if (owner == NULL) { 00568 clear_owner(op); 00569 return; 00570 } 00571 00572 /* next line added to allow objects which own objects */ 00573 /* Add a check for ownercounts in here, as I got into an endless loop 00574 * with the fireball owning a poison cloud which then owned the 00575 * fireball. I believe that was caused by one of the objects getting 00576 * freed and then another object replacing it. Since the ownercounts 00577 * didn't match, this check is valid and I believe that cause is valid. 00578 */ 00579 while (owner->owner 00580 && owner != owner->owner 00581 && owner->ownercount == owner->owner->count) 00582 owner = owner->owner; 00583 00584 /* IF the owner still has an owner, we did not resolve to a final owner. 00585 * so lets not add to that. 00586 */ 00587 if (owner->owner) { 00588 LOG(llevError, "owner id %d could not be resolved to a parent owner in set_owner(). This is bad!" 00589 "owner=%p owner->owner=%p owner->ownercount=%d owner->owner->count=%d\n", 00590 owner->count, owner, owner->owner, owner->ownercount, owner->owner->count); 00591 return; 00592 } 00593 00594 op->owner = owner; 00595 op->ownercount = owner->count; 00596 } 00597 00614 void copy_owner(object *op, object *clone) { 00615 object *owner = get_owner(clone); 00616 if (owner == NULL) { 00617 /* players don't have owners - they own themselves. Update 00618 * as appropriate. 00619 */ 00620 /*TODO owner=self is dangerous and should be avoided*/ 00621 if (clone->type == PLAYER) 00622 owner = clone; 00623 else 00624 return; 00625 } 00626 set_owner(op, owner); 00627 00628 } 00629 00639 void reset_object(object *op) { 00640 op->name = NULL; 00641 op->name_pl = NULL; 00642 op->title = NULL; 00643 op->race = NULL; 00644 op->slaying = NULL; 00645 op->skill = NULL; 00646 op->msg = NULL; 00647 op->materialname = NULL; 00648 op->lore = NULL; 00649 clear_object(op); 00650 } 00651 00659 void free_key_values(object *op) { 00660 key_value *i; 00661 key_value *next = NULL; 00662 00663 if (op->key_values == NULL) 00664 return; 00665 00666 for (i = op->key_values; i != NULL; i = next) { 00667 /* Store next *first*. */ 00668 next = i->next; 00669 00670 if (i->key) 00671 FREE_AND_CLEAR_STR(i->key); 00672 if (i->value) 00673 FREE_AND_CLEAR_STR(i->value); 00674 i->next = NULL; 00675 free(i); 00676 } 00677 00678 op->key_values = NULL; 00679 } 00680 00688 void clear_object(object *op) { 00689 00690 /*TODO this comment must be investigated*/ 00691 /* redo this to be simpler/more efficient. Was also seeing 00692 * crashes in the old code. Move this to the top - am 00693 * seeing periodic crashes in this code, and would like to have 00694 * as much info available as possible (eg, object name). 00695 */ 00696 free_key_values(op); 00697 free_dialog_information(op); 00698 00699 /* the memset will clear all these values for us, but we need 00700 * to reduce the refcount on them. 00701 */ 00702 if (op->name != NULL) FREE_AND_CLEAR_STR(op->name); 00703 if (op->name_pl != NULL) FREE_AND_CLEAR_STR(op->name_pl); 00704 if (op->title != NULL) FREE_AND_CLEAR_STR(op->title); 00705 if (op->race != NULL) FREE_AND_CLEAR_STR(op->race); 00706 if (op->slaying != NULL) FREE_AND_CLEAR_STR(op->slaying); 00707 if (op->skill != NULL) FREE_AND_CLEAR_STR(op->skill); 00708 if (op->msg != NULL) FREE_AND_CLEAR_STR(op->msg); 00709 if (op->lore != NULL) FREE_AND_CLEAR_STR(op->lore); 00710 if (op->materialname != NULL) FREE_AND_CLEAR_STR(op->materialname); 00711 if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage); 00712 00713 /* Remove object from friendly list if needed. */ 00714 if (QUERY_FLAG(op, FLAG_FRIENDLY)) 00715 remove_friendly_object(op); 00716 00717 memset((void *)((char *)op+offsetof(object, name)), 0, sizeof(object)-offsetof(object, name)); 00718 /* Below here, we clear things that are not done by the memset, 00719 * or set default values that are not zero. 00720 */ 00721 /* This is more or less true */ 00722 SET_FLAG(op, FLAG_REMOVED); 00723 00724 00725 op->contr = NULL; 00726 op->below = NULL; 00727 op->above = NULL; 00728 op->inv = NULL; 00729 op->container = NULL; 00730 op->env = NULL; 00731 op->more = NULL; 00732 op->head = NULL; 00733 op->map = NULL; 00734 op->active_next = NULL; 00735 op->active_prev = NULL; 00736 /* What is not cleared is next, prev, and count */ 00737 00738 op->expmul = 1.0; 00739 op->face = blank_face; 00740 op->attacked_by_count = -1; 00741 if (settings.casting_time) 00742 op->casting_time = -1; 00743 } 00744 00758 void copy_object(object *op2, object *op) { 00759 int is_freed = QUERY_FLAG(op, FLAG_FREED), is_removed = QUERY_FLAG(op, FLAG_REMOVED); 00760 00761 /* Decrement the refcounts, but don't bother zeroing the fields; 00762 they'll be overwritten by memcpy. */ 00763 if (op->name != NULL) free_string(op->name); 00764 if (op->name_pl != NULL) free_string(op->name_pl); 00765 if (op->anim_suffix != NULL) free_string(op->anim_suffix); 00766 if (op->title != NULL) free_string(op->title); 00767 if (op->race != NULL) free_string(op->race); 00768 if (op->slaying != NULL) free_string(op->slaying); 00769 if (op->skill != NULL) free_string(op->skill); 00770 if (op->msg != NULL) free_string(op->msg); 00771 if (op->lore != NULL) free_string(op->lore); 00772 if (op->materialname != NULL) free_string(op->materialname); 00773 if (op->custom_name != NULL) free_string(op->custom_name); 00774 if (op->discrete_damage != NULL) FREE_AND_CLEAR(op->discrete_damage); 00775 if (op->spell_tags != NULL) FREE_AND_CLEAR(op->spell_tags); 00776 00777 /* Basically, same code as from clear_object() */ 00778 00779 free_key_values(op); 00780 free_dialog_information(op); 00781 00782 /* op is the destination, op2 is the source. */ 00783 (void)memcpy((void *)((char *)op+offsetof(object, name)), 00784 (void *)((char *)op2+offsetof(object, name)), 00785 sizeof(object)-offsetof(object, name)); 00786 00787 if (is_freed) SET_FLAG(op, FLAG_FREED); 00788 if (is_removed) SET_FLAG(op, FLAG_REMOVED); 00789 if (op->name != NULL) add_refcount(op->name); 00790 if (op->name_pl != NULL) add_refcount(op->name_pl); 00791 if (op->anim_suffix != NULL) add_refcount(op->anim_suffix); 00792 if (op->title != NULL) add_refcount(op->title); 00793 if (op->race != NULL) add_refcount(op->race); 00794 if (op->slaying != NULL) add_refcount(op->slaying); 00795 if (op->skill != NULL) add_refcount(op->skill); 00796 if (op->lore != NULL) add_refcount(op->lore); 00797 if (op->msg != NULL) add_refcount(op->msg); 00798 if (op->custom_name != NULL) add_refcount(op->custom_name); 00799 if (op->materialname != NULL) add_refcount(op->materialname); 00800 if (op->discrete_damage != NULL) { 00801 op->discrete_damage = malloc(sizeof(sint16)*NROFATTACKS); 00802 memcpy(op->discrete_damage, op2->discrete_damage, sizeof(sint16)*NROFATTACKS); 00803 } 00804 00805 if (op->spell_tags != NULL) { 00806 op->spell_tags = malloc(sizeof(tag_t)*SPELL_TAG_SIZE); 00807 memcpy(op->spell_tags, op2->spell_tags, sizeof(tag_t)*SPELL_TAG_SIZE); 00808 } 00809 00810 /* If archetype is a temporary one, we need to update reference count, because 00811 * that archetype will be freed by free_object when the last object is removed. 00812 */ 00813 if (op->arch->reference_count > 0) 00814 op->arch->reference_count++; 00815 00816 if (op2->speed < 0) 00817 op->speed_left = op2->speed_left-RANDOM()%200/100.0; 00818 00819 /* Copy over key_values, if any. */ 00820 if (op2->key_values != NULL) { 00821 key_value *tail = NULL; 00822 key_value *i; 00823 00824 op->key_values = NULL; 00825 00826 for (i = op2->key_values; i != NULL; i = i->next) { 00827 key_value *new_link = malloc(sizeof(key_value)); 00828 00829 new_link->next = NULL; 00830 new_link->key = add_refcount(i->key); 00831 if (i->value) 00832 new_link->value = add_refcount(i->value); 00833 else 00834 new_link->value = NULL; 00835 00836 /* Try and be clever here, too. */ 00837 if (op->key_values == NULL) { 00838 op->key_values = new_link; 00839 tail = new_link; 00840 } else { 00841 tail->next = new_link; 00842 tail = new_link; 00843 } 00844 } 00845 } 00846 00847 /* This way, dialog information will be parsed again when/if needed. */ 00848 CLEAR_FLAG(op, FLAG_DIALOG_PARSED); 00849 00850 update_ob_speed(op); 00851 } 00852 00862 void copy_object_with_inv(object *src_ob, object *dest_ob) { 00863 object *walk, *tmp; 00864 copy_object(src_ob, dest_ob); 00865 00866 for (walk = src_ob->inv; walk != NULL; walk = walk->below) { 00867 tmp = get_object(); 00868 copy_object(walk, tmp); 00869 insert_ob_in_ob(tmp, dest_ob); 00870 } 00871 } 00872 00880 static void expand_objects(void) { 00881 int i; 00882 object *new; 00883 00884 new = (object *)CALLOC(OBJ_EXPAND, sizeof(object)); 00885 00886 if (new == NULL) 00887 fatal(OUT_OF_MEMORY); 00888 free_objects = new; 00889 new[0].prev = NULL; 00890 new[0].next = &new[1], 00891 SET_FLAG(&(new[0]), FLAG_REMOVED); 00892 SET_FLAG(&(new[0]), FLAG_FREED); 00893 00894 for (i = 1; i < OBJ_EXPAND-1; i++) { 00895 new[i].next = &new[i+1], 00896 new[i].prev = &new[i-1], 00897 SET_FLAG(&(new[i]), FLAG_REMOVED); 00898 SET_FLAG(&(new[i]), FLAG_FREED); 00899 } 00900 new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2], 00901 new[OBJ_EXPAND-1].next = NULL, 00902 SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_REMOVED); 00903 SET_FLAG(&(new[OBJ_EXPAND-1]), FLAG_FREED); 00904 00905 nrofallocobjects += OBJ_EXPAND; 00906 nroffreeobjects += OBJ_EXPAND; 00907 } 00908 00921 object *get_object(void) { 00922 object *op; 00923 00924 if (free_objects == NULL) { 00925 expand_objects(); 00926 } 00927 op = free_objects; 00928 #ifdef MEMORY_DEBUG 00929 /* The idea is hopefully by doing a realloc, the memory 00930 * debugging program will now use the current stack trace to 00931 * report leaks. 00932 */ 00933 /* FIXME: However this doesn't work since free_object2() sometimes add 00934 * objects back to the free_objects linked list, and some functions mess 00935 * with the object after return of free_object2(). This is bad and should be 00936 * fixed. But it would need fairly extensive changes and a lot of debugging. 00937 * So until that is fixed, skip realloc() here unless MEMORY_DEBUG is set to 00938 * a value greater than 1. We do this in order at least make MEMORY_DEBUG 00939 * slightly useful. 00940 */ 00941 #if MEMORY_DEBUG > 1 00942 op = realloc(op, sizeof(object)); 00943 #endif 00944 SET_FLAG(op, FLAG_REMOVED); 00945 SET_FLAG(op, FLAG_FREED); 00946 #endif 00947 00948 if (!QUERY_FLAG(op, FLAG_FREED)) { 00949 LOG(llevError, "Fatal: Getting busy object.\n"); 00950 #ifdef MANY_CORES 00951 abort(); 00952 #endif 00953 } 00954 free_objects = op->next; 00955 if (free_objects != NULL) 00956 free_objects->prev = NULL; 00957 op->count = ++ob_count; 00958 op->name = NULL; 00959 op->name_pl = NULL; 00960 op->title = NULL; 00961 op->race = NULL; 00962 op->slaying = NULL; 00963 op->skill = NULL; 00964 op->lore = NULL; 00965 op->msg = NULL; 00966 op->materialname = NULL; 00967 op->next = objects; 00968 op->prev = NULL; 00969 op->active_next = NULL; 00970 op->active_prev = NULL; 00971 op->discrete_damage = NULL; 00972 op->spell_tags = NULL; 00973 if (objects != NULL) 00974 objects->prev = op; 00975 objects = op; 00976 clear_object(op); 00977 SET_FLAG(op, FLAG_REMOVED); 00978 nroffreeobjects--; 00979 return op; 00980 } 00981 00990 void update_turn_face(object *op) { 00991 if (!QUERY_FLAG(op, FLAG_IS_TURNABLE) || op->arch == NULL) 00992 return; 00993 SET_ANIMATION(op, op->direction); 00994 update_object(op, UP_OBJ_FACE); 00995 } 00996 01008 void update_ob_speed(object *op) { 01009 /* FIXME what the hell is this crappy hack?*/ 01010 extern int arch_init; 01011 01012 /* No reason putting the archetypes objects on the speed list, 01013 * since they never really need to be updated. 01014 */ 01015 01016 if (QUERY_FLAG(op, FLAG_FREED) && op->speed) { 01017 LOG(llevError, "Object %s is freed but has speed.\n", op->name); 01018 #ifdef MANY_CORES 01019 abort(); 01020 #else 01021 op->speed = 0; 01022 #endif 01023 } 01024 if (arch_init) { 01025 return; 01026 } 01027 if (FABS(op->speed) > MIN_ACTIVE_SPEED) { 01028 /* If already on active list, don't do anything */ 01029 /* TODO this check can probably be simplified a lot */ 01030 if (op->active_next || op->active_prev || op == active_objects) 01031 return; 01032 01033 /* process_events() expects us to insert the object at the beginning 01034 * of the list. */ 01035 op->active_next = active_objects; 01036 if (op->active_next != NULL) 01037 op->active_next->active_prev = op; 01038 active_objects = op; 01039 } else { 01040 /* If not on the active list, nothing needs to be done */ 01041 if (!op->active_next && !op->active_prev && op != active_objects) 01042 return; 01043 01044 if (op->active_prev == NULL) { 01045 active_objects = op->active_next; 01046 if (op->active_next != NULL) 01047 op->active_next->active_prev = NULL; 01048 } else { 01049 op->active_prev->active_next = op->active_next; 01050 if (op->active_next) 01051 op->active_next->active_prev = op->active_prev; 01052 } 01053 op->active_next = NULL; 01054 op->active_prev = NULL; 01055 } 01056 } 01057 01070 void remove_from_active_list(object *op) { 01071 /* If not on the active list, nothing needs to be done */ 01072 if (!op->active_next && !op->active_prev && op != active_objects) 01073 return; 01074 01075 if (op->active_prev == NULL) { 01076 active_objects = op->active_next; 01077 if (op->active_next != NULL) 01078 op->active_next->active_prev = NULL; 01079 } else { 01080 op->active_prev->active_next = op->active_next; 01081 if (op->active_next) 01082 op->active_next->active_prev = op->active_prev; 01083 } 01084 op->active_next = NULL; 01085 op->active_prev = NULL; 01086 } 01087 01112 void update_object(object *op, int action) { 01113 int update_now = 0, flags; 01114 MoveType move_on, move_off, move_block, move_slow; 01115 object *pl; 01116 01117 if (op == NULL) { 01118 /* this should never happen */ 01119 LOG(llevDebug, "update_object() called for NULL object.\n"); 01120 return; 01121 } 01122 01123 if (op->env != NULL) { 01124 /* Animation is currently handled by client, so nothing 01125 * to do in this case. 01126 */ 01127 return; 01128 } 01129 01130 /* If the map is saving, don't do anything as everything is 01131 * going to get freed anyways. 01132 */ 01133 if (!op->map || op->map->in_memory == MAP_SAVING) 01134 return; 01135 01136 /* make sure the object is within map boundaries */ 01137 if (op->x < 0 || op->x >= MAP_WIDTH(op->map) 01138 || op->y < 0 || op->y >= MAP_HEIGHT(op->map)) { 01139 LOG(llevError, "update_object() called for object out of map!\n"); 01140 #ifdef MANY_CORES 01141 abort(); 01142 #endif 01143 return; 01144 } 01145 01146 flags = GET_MAP_FLAGS(op->map, op->x, op->y); 01147 SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NEED_UPDATE); 01148 move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y); 01149 move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y); 01150 move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y); 01151 move_off = GET_MAP_MOVE_OFF(op->map, op->x, op->y); 01152 01153 if (action == UP_OBJ_INSERT) { 01154 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) && !(flags&P_BLOCKSVIEW)) 01155 update_now = 1; 01156 01157 if (QUERY_FLAG(op, FLAG_NO_MAGIC) && !(flags&P_NO_MAGIC)) 01158 update_now = 1; 01159 01160 if (QUERY_FLAG(op, FLAG_DAMNED) && !(flags&P_NO_CLERIC)) 01161 update_now = 1; 01162 01163 if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags&P_IS_ALIVE)) 01164 update_now = 1; 01165 01166 if ((move_on|op->move_on) != move_on) 01167 update_now = 1; 01168 if ((move_off|op->move_off) != move_off) 01169 update_now = 1; 01170 /* This isn't perfect, but I don't expect a lot of objects to 01171 * to have move_allow right now. 01172 */ 01173 if (((move_block|op->move_block)&~op->move_allow) != move_block) 01174 update_now = 1; 01175 if ((move_slow|op->move_slow) != move_slow) 01176 update_now = 1; 01177 01178 if (op->type == PLAYER) 01179 update_now = 1; 01180 /* if the object is being removed, we can't make intelligent 01181 * decisions, because remove_ob can't really pass the object 01182 * that is being removed. 01183 */ 01184 } else if (action == UP_OBJ_REMOVE) { 01185 update_now = 1; 01186 } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) { 01187 /* In addition to sending info to client, need to update space 01188 * information. 01189 */ 01190 if (action == UP_OBJ_CHANGE) 01191 update_now = 1; 01192 01193 /* There is a player on this space - we may need to send an 01194 * update to the client. 01195 * If this object is supposed to be animated by the client, 01196 * nothing to do here - let the client animate it. 01197 * We can't use FLAG_ANIMATE, as that is basically set for 01198 * all objects with multiple faces, regardless if they are animated. 01199 * (levers have it set for example). 01200 */ 01201 if (flags&P_PLAYER 01202 && !QUERY_FLAG(op, FLAG_CLIENT_ANIM_SYNC) 01203 && !QUERY_FLAG(op, FLAG_CLIENT_ANIM_RANDOM)) { 01204 pl = GET_MAP_PLAYER(op->map, op->x, op->y); 01205 01206 /* If update_look is set, we're going to send this entire space 01207 * to the client, so no reason to send face information now. 01208 */ 01209 if (!pl->contr->socket.update_look) { 01210 esrv_update_item(UPD_FACE, pl, op); 01211 } 01212 } 01213 } else { 01214 LOG(llevError, "update_object called with invalid action: %d\n", action); 01215 } 01216 01217 if (update_now) { 01218 SET_MAP_FLAGS(op->map, op->x, op->y, flags|P_NO_ERROR|P_NEED_UPDATE); 01219 update_position(op->map, op->x, op->y); 01220 } 01221 01222 if (op->more != NULL) 01223 update_object(op->more, action); 01224 } 01225 01238 void free_object(object *ob) { 01239 free_object2(ob, 0); 01240 } 01241 01258 void free_object2(object *ob, int free_inventory) { 01259 object *tmp, *op; 01260 01261 if (!QUERY_FLAG(ob, FLAG_REMOVED)) { 01262 StringBuffer *sb; 01263 char *diff; 01264 01265 LOG(llevDebug, "Free object called with non removed object\n"); 01266 sb = stringbuffer_new(); 01267 dump_object(ob, sb); 01268 diff = stringbuffer_finish(sb); 01269 LOG(llevError, diff); 01270 free(diff); 01271 #ifdef MANY_CORES 01272 abort(); 01273 #endif 01274 } 01275 if (QUERY_FLAG(ob, FLAG_FRIENDLY)) { 01276 LOG(llevMonster, "Warning: tried to free friendly object.\n"); 01277 remove_friendly_object(ob); 01278 } 01279 if (QUERY_FLAG(ob, FLAG_FREED)) { 01280 StringBuffer *sb; 01281 char *diff; 01282 01283 sb = stringbuffer_new(); 01284 dump_object(ob, sb); 01285 diff = stringbuffer_finish(sb); 01286 LOG(llevError, "Trying to free freed object.\n%s\n", diff); 01287 free(diff); 01288 return; 01289 } 01290 01291 /* Handle for plugin destroy event */ 01292 execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING); 01293 01294 if (ob->inv) { 01295 /* Only if the space blocks everything do we not process - 01296 * if some form of movemnt is allowed, let objects 01297 * drop on that space. 01298 */ 01299 if (free_inventory 01300 || ob->map == NULL 01301 || ob->map->in_memory != MAP_IN_MEMORY 01302 || (GET_MAP_MOVE_BLOCK(ob->map, ob->x, ob->y) == MOVE_ALL)) { 01303 op = ob->inv; 01304 while (op != NULL) { 01305 tmp = op->below; 01306 remove_ob(op); 01307 free_object2(op, free_inventory); 01308 op = tmp; 01309 } 01310 } else { /* Put objects in inventory onto this space */ 01311 op = ob->inv; 01312 while (op != NULL) { 01313 tmp = op->below; 01314 remove_ob(op); 01315 if (QUERY_FLAG(op, FLAG_STARTEQUIP)||QUERY_FLAG(op, FLAG_NO_DROP) 01316 || op->type == RUNE 01317 || op->type == TRAP 01318 || QUERY_FLAG(op, FLAG_IS_A_TEMPLATE)) 01319 free_object(op); 01320 else { 01321 object *part; 01322 01323 /* If it's a multi-tile object, scatter dropped items randomly */ 01324 if (ob->more) { 01325 int partcount = 0; 01326 /* Get the number of non-head parts */ 01327 for (part = ob; part; part = part->more) { 01328 partcount++; 01329 } 01330 /* Select a random part */ 01331 partcount = RANDOM()%partcount; 01332 for (part = ob; partcount > 0; partcount--) { 01333 part = part->more; 01334 } 01335 } else { 01336 part = ob; 01337 } 01338 01339 if (QUERY_FLAG(op, FLAG_ALIVE)) { 01340 int pos; 01341 01342 pos = find_free_spot(op, part->map, part->x, part->y, 0, SIZEOFFREE); 01343 if (pos == -1) 01344 free_object(op); 01345 else { 01346 op->x = part->x+freearr_x[pos]; 01347 op->y = part->y+freearr_y[pos]; 01348 insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */ 01349 } 01350 } else { 01351 op->x = part->x; 01352 op->y = part->y; 01353 insert_ob_in_map(op, part->map, NULL, 0); /* Insert in same map as the envir */ 01354 } 01355 } 01356 op = tmp; 01357 } 01358 } 01359 } 01360 01361 if (ob->more != NULL) { 01362 free_object2(ob->more, free_inventory); 01363 ob->more = NULL; 01364 } 01365 01366 /* Remove object from the active list */ 01367 ob->speed = 0; 01368 update_ob_speed(ob); 01369 01370 SET_FLAG(ob, FLAG_FREED); 01371 ob->count = 0; 01372 01373 /* Remove this object from the list of used objects */ 01374 if (ob->prev == NULL) { 01375 objects = ob->next; 01376 if (objects != NULL) 01377 objects->prev = NULL; 01378 } else { 01379 ob->prev->next = ob->next; 01380 if (ob->next != NULL) 01381 ob->next->prev = ob->prev; 01382 } 01383 01384 if (ob->name != NULL) FREE_AND_CLEAR_STR(ob->name); 01385 if (ob->name_pl != NULL) FREE_AND_CLEAR_STR(ob->name_pl); 01386 if (ob->title != NULL) FREE_AND_CLEAR_STR(ob->title); 01387 if (ob->race != NULL) FREE_AND_CLEAR_STR(ob->race); 01388 if (ob->slaying != NULL) FREE_AND_CLEAR_STR(ob->slaying); 01389 if (ob->skill != NULL) FREE_AND_CLEAR_STR(ob->skill); 01390 if (ob->lore != NULL) FREE_AND_CLEAR_STR(ob->lore); 01391 if (ob->msg != NULL) FREE_AND_CLEAR_STR(ob->msg); 01392 if (ob->materialname != NULL) FREE_AND_CLEAR_STR(ob->materialname); 01393 if (ob->discrete_damage != NULL) FREE_AND_CLEAR(ob->discrete_damage); 01394 if (ob->spell_tags) FREE_AND_CLEAR(ob->spell_tags); 01395 01396 /* Why aren't events freed? */ 01397 free_key_values(ob); 01398 01399 free_dialog_information(ob); 01400 01401 /* Test whether archetype is a temporary one, and if so look whether it should be trashed. */ 01402 if (ob->arch && ob->arch->reference_count > 0) { 01403 if (--ob->arch->reference_count == 0) { 01404 free_arch(ob->arch); 01405 } 01406 } 01407 01408 #if defined(MEMORY_DEBUG) && (MEMORY_DEBUG > 2) 01409 /* memset() to clear it then set flags and finally free it. This will 01410 * help detect bad use after return. 01411 */ 01412 memset(ob, 0, sizeof(object)); 01413 SET_FLAG(ob, FLAG_REMOVED); 01414 SET_FLAG(ob, FLAG_FREED); 01415 free(ob); 01416 #else 01417 /* Now link it with the free_objects list: */ 01418 ob->prev = NULL; 01419 ob->next = free_objects; 01420 if (free_objects != NULL) 01421 free_objects->prev = ob; 01422 free_objects = ob; 01423 nroffreeobjects++; 01424 #endif 01425 } 01426 01433 int count_free(void) { 01434 int i = 0; 01435 object *tmp = free_objects; 01436 01437 while (tmp != NULL) 01438 tmp = tmp->next, 01439 i++; 01440 return i; 01441 } 01442 01449 int count_used(void) { 01450 int i = 0; 01451 object *tmp = objects; 01452 01453 while (tmp != NULL) 01454 tmp = tmp->next, 01455 i++; 01456 return i; 01457 } 01458 01465 int count_active(void) { 01466 int i = 0; 01467 object *tmp = active_objects; 01468 01469 while (tmp != NULL) 01470 tmp = tmp->active_next, 01471 i++; 01472 return i; 01473 } 01474 01489 void sub_weight(object *op, signed long weight) { 01490 while (op != NULL) { 01491 if (op->type == CONTAINER) { 01492 weight = (signed long)(weight*(100-op->stats.Str)/100); 01493 } 01494 op->carrying -= weight; 01495 op = op->env; 01496 } 01497 } 01498 01515 void remove_ob(object *op) { 01516 object *tmp, *last = NULL; 01517 object *otmp; 01518 tag_t tag; 01519 int check_walk_off; 01520 mapstruct *m; 01521 sint16 x, y; 01522 01523 if (QUERY_FLAG(op, FLAG_REMOVED)) { 01524 StringBuffer *sb; 01525 char *diff; 01526 01527 sb = stringbuffer_new(); 01528 dump_object(op, sb); 01529 diff = stringbuffer_finish(sb); 01530 LOG(llevError, "Trying to remove removed object.\n%s\n", diff); 01531 free(diff); 01532 abort(); 01533 } 01534 if (op->more != NULL) 01535 remove_ob(op->more); 01536 01537 SET_FLAG(op, FLAG_REMOVED); 01538 01539 /* 01540 * In this case, the object to be removed is in someones 01541 * inventory. 01542 */ 01543 /* TODO try to call a generic inventory weight adjusting function like sub_weight */ 01544 if (op->env != NULL) { 01545 if (op->nrof) 01546 sub_weight(op->env, op->weight*op->nrof); 01547 else 01548 sub_weight(op->env, op->weight+op->carrying); 01549 01550 /* Update in two cases: item is in a player, or in a container the player is looking into. */ 01551 if (op->env->contr != NULL && op->head == NULL) { 01552 if (LOOK_OBJ(op)) 01553 esrv_del_item(op->env->contr, op->count); 01554 } else if (op->env->type == CONTAINER && QUERY_FLAG(op->env, FLAG_APPLIED)) { 01555 player *pl = NULL; 01556 01557 if (op->env->env && op->env->env->contr) 01558 /* Container is in player's inventory. */ 01559 pl = op->env->env->contr; 01560 else if (op->env->map) { 01561 /* Container on map, look above for player. */ 01562 object *above = op->env->above; 01563 01564 while (above && !above->contr) 01565 above = above->above; 01566 if (above) 01567 pl = above->contr; 01568 } 01569 if (pl && LOOK_OBJ(op)) 01570 esrv_del_item(pl, op->count); 01571 } 01572 01573 /* NO_FIX_PLAYER is set when a great many changes are being 01574 * made to players inventory. If set, avoiding the call 01575 * to save cpu time. 01576 */ 01577 if ((otmp = get_player_container(op->env)) != NULL 01578 && otmp->contr 01579 && !QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER)) 01580 fix_object(otmp); 01581 01582 if (op->above != NULL) 01583 op->above->below = op->below; 01584 else 01585 op->env->inv = op->below; 01586 01587 if (op->below != NULL) 01588 op->below->above = op->above; 01589 01590 /* we set up values so that it could be inserted into 01591 * the map, but we don't actually do that - it is up 01592 * to the caller to decide what we want to do. 01593 */ 01594 op->x = op->env->x; 01595 op->y = op->env->y; 01596 op->ox = op->x; 01597 op->oy = op->y; 01598 op->map = op->env->map; 01599 op->above = NULL; 01600 op->below = NULL; 01601 op->env = NULL; 01602 return; 01603 } 01604 01605 /* If we get here, we are removing it from a map */ 01606 if (op->map == NULL) 01607 return; 01608 01609 if (op->contr != NULL && !op->contr->hidden) 01610 op->map->players--; 01611 01612 x = op->x; 01613 y = op->y; 01614 m = get_map_from_coord(op->map, &x, &y); 01615 01616 if (!m) { 01617 LOG(llevError, "remove_ob called when object was on map but appears to not be within valid coordinates? %s (%d,%d)\n", op->map->path, op->x, op->y); 01618 abort(); 01619 } 01620 if (op->map != m) { 01621 LOG(llevError, "remove_ob: Object not really on map it claimed to be on? %s != %s, %d,%d != %d,%d\n", op->map->path, m->path, op->x, op->y, x, y); 01622 } 01623 01624 /* link the object above us */ 01625 if (op->above) 01626 op->above->below = op->below; 01627 else 01628 SET_MAP_TOP(m, x, y, op->below); /* we were top, set new top */ 01629 01630 /* Relink the object below us, if there is one */ 01631 if (op->below) { 01632 op->below->above = op->above; 01633 } else { 01634 /* Nothing below, which means we need to relink map object for this space 01635 * use translated coordinates in case some oddness with map tiling is 01636 * evident 01637 */ 01638 /*TODO is this check really needed?*/ 01639 if (GET_MAP_OB(m, x, y) != op) { 01640 StringBuffer *sb; 01641 char *diff; 01642 01643 sb = stringbuffer_new(); 01644 dump_object(op, sb); 01645 diff = stringbuffer_finish(sb); 01646 LOG(llevError, "remove_ob: GET_MAP_OB does not return object to be removed even though it appears to be on the bottom?\n%s\n", diff); 01647 free(diff); 01648 01649 sb = stringbuffer_new(); 01650 dump_object(GET_MAP_OB(m, x, y), sb); 01651 diff = stringbuffer_finish(sb); 01652 LOG(llevError, "%s\n", diff); 01653 free(diff); 01654 } 01655 SET_MAP_OB(m, x, y, op->above); /* goes on above it. */ 01656 } 01657 op->above = NULL; 01658 op->below = NULL; 01659 01660 if (op->map->in_memory == MAP_SAVING) 01661 return; 01662 01663 tag = op->count; 01664 check_walk_off = !QUERY_FLAG(op, FLAG_NO_APPLY); 01665 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) { 01666 /* No point updating the players look faces if he is the object 01667 * being removed. 01668 */ 01669 01670 if (tmp->type == PLAYER && tmp != op) { 01671 /* If a container that the player is currently using somehow gets 01672 * removed (most likely destroyed), update the player view 01673 * appropriately. 01674 */ 01675 if (tmp->container == op) { 01676 CLEAR_FLAG(op, FLAG_APPLIED); 01677 tmp->container = NULL; 01678 } 01679 tmp->contr->socket.update_look = 1; 01680 } 01681 /* See if player moving off should effect something */ 01682 if (check_walk_off 01683 && ((op->move_type&tmp->move_off) && (op->move_type&~tmp->move_off&~tmp->move_block) == 0)) { 01684 ob_move_on(tmp, op, NULL); 01685 if (was_destroyed(op, tag)) { 01686 LOG(llevError, "BUG: remove_ob(): name %s, archname %s destroyed leaving object\n", tmp->name, tmp->arch->name); 01687 } 01688 } 01689 01690 /* Eneq(@csd.uu.se): Fixed this to skip tmp->above=tmp */ 01691 if (tmp->above == tmp) 01692 tmp->above = NULL; 01693 last = tmp; 01694 } 01695 /* last == NULL or there are no objects on this space */ 01696 if (last == NULL) { 01697 /* set P_NEED_UPDATE, otherwise update_position will complain. In theory, 01698 * we could preserve the flags (GET_MAP_FLAGS), but update_position figures 01699 * those out anyways, and if there are any flags set right now, they won't 01700 * be correct anyways. 01701 */ 01702 SET_MAP_FLAGS(op->map, op->x, op->y, P_NEED_UPDATE); 01703 update_position(op->map, op->x, op->y); 01704 } else 01705 update_object(last, UP_OBJ_REMOVE); 01706 01707 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW)|| (op->glow_radius != 0)) 01708 update_all_los(op->map, op->x, op->y); 01709 } 01710 01724 object *merge_ob(object *op, object *top) { 01725 if (!op->nrof) 01726 return NULL; 01727 01728 if (top == NULL) 01729 for (top = op; top != NULL && top->above != NULL; top = top->above) 01730 ; 01731 for (; top != NULL; top = top->below) { 01732 if (top == op) 01733 continue; 01734 if (can_merge(op, top)) { 01735 increase_ob_nr(top, op->nrof); 01736 op->weight = 0; /* Don't want any adjustements now */ 01737 remove_ob(op); 01738 free_object(op); 01739 return top; 01740 } 01741 } 01742 return NULL; 01743 } 01744 01761 object *insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y) { 01762 object *tmp; 01763 01764 if (op->head) 01765 op = op->head; 01766 for (tmp = op; tmp; tmp = tmp->more) { 01767 tmp->x = x+tmp->arch->clone.x; 01768 tmp->y = y+tmp->arch->clone.y; 01769 if (op != tmp && !tmp->map) 01770 tmp->map = op->map ? op->map : m; 01771 } 01772 return insert_ob_in_map(op, m, originator, flag); 01773 } 01774 01792 void merge_spell(object *op, sint16 x, sint16 y) { 01793 object *tmp, *above; 01794 int i; 01795 01796 /* We try to do some merging of spell objects - if something has same owner, 01797 * is same type of spell, and going in the same direction, it is somewhat 01798 * mergable. 01799 * 01800 * If the spell object has an other_arch, don't merge - when the spell 01801 * does something, like explodes, it will use this other_arch, and 01802 * if we merge, there is no easy way to make the correct values be 01803 * set on this new object (values should be doubled, tripled, etc.) 01804 * 01805 * We also care about speed - only process objects that will not be 01806 * active this tick. Without this, the results are incorrect - think 01807 * of a case where tmp would normally get processed this tick, but 01808 * get merges with op, which does not get processed. 01809 */ 01810 for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = above) { 01811 above = tmp->above; 01812 01813 if (op->type == tmp->type 01814 && op->subtype == tmp->subtype 01815 && op->direction == tmp->direction 01816 && op->owner == tmp->owner && op->ownercount == tmp->ownercount 01817 && op->range == tmp->range 01818 && op->stats.wc == tmp->stats.wc 01819 && op->level == tmp->level 01820 && op->attacktype == tmp->attacktype 01821 && op->speed == tmp->speed 01822 && !tmp->other_arch 01823 && (tmp->speed_left+tmp->speed) < 0.0 01824 && op != tmp) { 01825 /* Quick test - if one or the other objects already have hash tables 01826 * set up, and that hash bucket contains a value that doesn't 01827 * match what we want to set it up, we won't be able to merge. 01828 * Note that these two if statements are the same, except 01829 * for which object they are checking against. They could 01830 * be merged, but the line wrapping would be large enough 01831 * that IMO it would become difficult to read the different clauses 01832 * so its cleaner just to do 2 statements - MSW 01833 */ 01834 if (op->spell_tags 01835 && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp) 01836 && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0) 01837 continue; 01838 01839 if (tmp->spell_tags 01840 && !OB_SPELL_TAG_MATCH(tmp, op->stats.maxhp) 01841 && OB_SPELL_TAG_HASH(tmp, op->stats.maxhp) != 0) 01842 continue; 01843 01844 /* If we merge, the data from tmp->spell_tags gets copied into op. 01845 * so we need to make sure that slot isn't filled up. 01846 */ 01847 if (tmp->spell_tags 01848 && !OB_SPELL_TAG_MATCH(tmp, tmp->stats.maxhp) 01849 && OB_SPELL_TAG_HASH(tmp, tmp->stats.maxhp) != 0) 01850 continue; 01851 01852 /* If both objects have spell_tags, we need to see if there are conflicting 01853 * values - if there are, we won't be able to merge then. 01854 */ 01855 if (tmp->spell_tags && op->spell_tags) { 01856 int need_copy = 0; 01857 01858 for (i = 0; i < SPELL_TAG_SIZE; i++) { 01859 /* If the two tag values in the hash are set, but are 01860 * not set to the same value, then these objects 01861 * can not be merged. 01862 */ 01863 if (op->spell_tags[i] && tmp->spell_tags[i] 01864 && op->spell_tags[i] != tmp->spell_tags[i]) { 01865 statistics.spell_hash_full++; 01866 break; 01867 } 01868 /* If one tag is set and the other is not, that is 01869 * fine, but we have to note that we need to copy 01870 * the data in that case. 01871 */ 01872 if ((!op->spell_tags[i] && tmp->spell_tags[i]) 01873 || (op->spell_tags[i] && !tmp->spell_tags[i])) { 01874 need_copy = 1; 01875 } 01876 } 01877 /* If we did not get through entire array, it means 01878 * we got a conflicting hash, and so we won't be 01879 * able to merge these - just continue processing 01880 * object on this space. 01881 */ 01882 if (i <= SPELL_TAG_SIZE) 01883 continue; 01884 01885 /* Ok - everything checked out - we should be able to 01886 * merge tmp in op. So lets copy the tag data if 01887 * needed. Note that this is a selective copy, as 01888 * we don't want to clear values that may be set in op. 01889 */ 01890 if (need_copy) { 01891 for (i = 0; i < SPELL_TAG_SIZE; i++) 01892 if (!op->spell_tags[i] 01893 && tmp->spell_tags[i] 01894 && tmp->spell_tags[i] != op->stats.maxhp) 01895 op->spell_tags[i] = tmp->spell_tags[i]; 01896 } 01897 FREE_AND_CLEAR(tmp->spell_tags); 01898 } 01899 01900 /* if tmp has a spell_tags table, copy it to op and free tmps */ 01901 if (tmp->spell_tags && !op->spell_tags) { 01902 op->spell_tags = tmp->spell_tags; 01903 tmp->spell_tags = NULL; 01904 01905 /* We don't need to keep a copy of our maxhp value 01906 * in the copied over value 01907 */ 01908 if (OB_SPELL_TAG_MATCH(op, op->stats.maxhp)) 01909 OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0; 01910 } 01911 01912 /* For spells to work correctly, we need to record what spell 01913 * tags we've merged in with this effect. This is used 01914 * in ok_to_put_more() to see if a spell effect is already on 01915 * the space. 01916 */ 01917 if (op->stats.maxhp != tmp->stats.maxhp) { 01918 #ifdef OBJECT_DEBUG 01919 /* This if statement should never happen - the logic above should 01920 * have prevented it. It is a problem, because by now its possible 01921 * we've destroyed the spell_tags in tmp, so we can't really 01922 * just bail out. 01923 */ 01924 01925 if (op->spell_tags 01926 && OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) != 0 01927 && !OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp)) { 01928 LOG(llevError, "insert_ob_in_map: Got non matching spell tags: %d != %d\n", OB_SPELL_TAG_HASH(op, tmp->stats.maxhp), tmp->stats.maxhp); 01929 } 01930 #endif 01931 if (!op->spell_tags) 01932 op->spell_tags = calloc(1, SPELL_TAG_SIZE*sizeof(tag_t)); 01933 01934 OB_SPELL_TAG_HASH(op, tmp->stats.maxhp) = tmp->stats.maxhp; 01935 } 01936 01937 statistics.spell_merges++; 01938 op->speed_left = MAX(op->speed_left, tmp->speed_left); 01939 01940 if (tmp->duration != op->duration) { 01941 /* We need to use tmp_dam here because otherwise the 01942 * calculations can overflow the size of stats.dam. 01943 */ 01944 int tmp_dam = tmp->stats.dam*(tmp->duration+1)+ 01945 op->stats.dam*(op->duration+1); 01946 01947 op->duration = MAX(op->duration, tmp->duration); 01948 tmp_dam /= (op->duration+1); 01949 op->stats.dam = tmp_dam+1; 01950 } else { 01951 /* in this case, duration is the same, so simply adding 01952 * up damage works. 01953 */ 01954 op->stats.dam += tmp->stats.dam; 01955 } 01956 01957 remove_ob(tmp); 01958 free_object(tmp); 01959 } 01960 } 01961 } 01962 01992 object *insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag) { 01993 object *tmp, *top, *floor = NULL; 01994 sint16 x, y; 01995 01996 if (QUERY_FLAG(op, FLAG_FREED)) { 01997 LOG(llevError, "Trying to insert freed object!\n"); 01998 return NULL; 01999 } 02000 if (m == NULL) { 02001 StringBuffer *sb; 02002 char *diff; 02003 02004 sb = stringbuffer_new(); 02005 dump_object(op, sb); 02006 diff = stringbuffer_finish(sb); 02007 LOG(llevError, "Trying to insert in null-map!\n%s\n", diff); 02008 free(diff); 02009 return op; 02010 } 02011 if (out_of_map(m, op->x, op->y)) { 02012 StringBuffer *sb; 02013 char *diff; 02014 02015 sb = stringbuffer_new(); 02016 dump_object(op, sb); 02017 diff = stringbuffer_finish(sb); 02018 LOG(llevError, "Trying to insert object outside the map.\n%s\n", diff); 02019 free(diff); 02020 #ifdef MANY_CORES 02021 /* Better to catch this here, as otherwise the next use of this object 02022 * is likely to cause a crash. Better to find out where it is getting 02023 * improperly inserted. 02024 */ 02025 abort(); 02026 #endif 02027 return op; 02028 } 02029 if (!QUERY_FLAG(op, FLAG_REMOVED)) { 02030 StringBuffer *sb; 02031 char *diff; 02032 02033 sb = stringbuffer_new(); 02034 dump_object(op, sb); 02035 diff = stringbuffer_finish(sb); 02036 LOG(llevError, "Trying to insert (map) inserted object.\n%s\n", diff); 02037 free(diff); 02038 return op; 02039 } 02040 if (op->more != NULL) { 02041 /* The part may be on a different map. */ 02042 02043 object *more = op->more; 02044 02045 /* We really need the caller to normalize coordinates - if 02046 * we set the map, that doesn't work if the location is within 02047 * a map and this is straddling an edge. So only if coordinate 02048 * is clear wrong do we normalize it. 02049 */ 02050 if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) { 02051 /* Debugging information so you can see the last coordinates this object had */ 02052 more->ox = more->x; 02053 more->oy = more->y; 02054 more->map = get_map_from_coord(m, &more->x, &more->y); 02055 } else if (!more->map) { 02056 /* For backwards compatibility - when not dealing with tiled maps, 02057 * more->map should always point to the parent. 02058 */ 02059 more->map = m; 02060 } 02061 02062 if (insert_ob_in_map(more, more->map, originator, flag) == NULL) { 02063 if (!op->head) 02064 LOG(llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); 02065 return NULL; 02066 } 02067 } 02068 CLEAR_FLAG(op, FLAG_REMOVED); 02069 02070 /* Debugging information so you can see the last coordinates this object had */ 02071 op->ox = op->x; 02072 op->oy = op->y; 02073 x = op->x; 02074 y = op->y; 02075 op->map = get_map_from_coord(m, &x, &y); 02076 02077 /* this has to be done after we translate the coordinates. */ 02078 if (op->nrof 02079 && !(flag&INS_NO_MERGE) 02080 && op->type != SPELL_EFFECT) { 02081 for (tmp = GET_MAP_OB(op->map, x, y); tmp != NULL; tmp = tmp->above) { 02082 if (can_merge(op, tmp)) { 02083 op->nrof += tmp->nrof; 02084 remove_ob(tmp); 02085 free_object(tmp); 02086 } 02087 } 02088 } else if (op->type == SPELL_EFFECT 02089 && !op->range 02090 && !op->other_arch 02091 && (op->speed_left+op->speed) < 0.0) { 02092 merge_spell(op, x, y); 02093 } 02094 02095 /* Ideally, the caller figures this out. However, it complicates a lot 02096 * of areas of callers (eg, anything that uses find_free_spot would now 02097 * need extra work 02098 */ 02099 if (op->map != m) { 02100 /* coordinates should not change unless map also changes */ 02101 op->x = x; 02102 op->y = y; 02103 } 02104 02105 if (op->type != LAMP) 02106 /* lamps use the FLAG_APPLIED to keep the light/unlit status, so don't reset it. 02107 Other objects just get unapplied, since the container "drops" them. */ 02108 CLEAR_FLAG(op, FLAG_APPLIED); 02109 CLEAR_FLAG(op, FLAG_INV_LOCKED); 02110 if (!QUERY_FLAG(op, FLAG_ALIVE)) 02111 CLEAR_FLAG(op, FLAG_NO_STEAL); 02112 02113 /* In many places, a player is passed as the originator, which 02114 * is fine. However, if the player is on a transport, they are not 02115 * actually on the map, so we can't use them for the linked pointers, 02116 * nor should the walk on function below use them either. 02117 */ 02118 if (originator && originator->contr && originator->contr->transport) 02119 originator = originator->contr->transport; 02120 02121 if (flag&INS_BELOW_ORIGINATOR) { 02122 if (originator->map != op->map 02123 || originator->x != op->x 02124 || originator->y != op->y) { 02125 LOG(llevError, "insert_ob_in_map called with INS_BELOW_ORIGINATOR when originator not on same space!\n"); 02126 abort(); 02127 } 02128 op->above = originator; 02129 op->below = originator->below; 02130 if (op->below) 02131 op->below->above = op; 02132 else 02133 SET_MAP_OB(op->map, op->x, op->y, op); 02134 /* since *below *originator, no need to update top */ 02135 originator->below = op; 02136 } else { 02137 /* If there are other objects, then */ 02138 /* This test is incorrect i think, as ins_above_floor_only needs the floor variable 02139 if ((!(flag&INS_MAP_LOAD)) && ((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) { 02140 */ 02141 if (((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) { 02142 object *last = NULL; 02143 02144 /* 02145 * If there are multiple objects on this space, we do some trickier handling. 02146 * We've already dealt with merging if appropriate. 02147 * Generally, we want to put the new object on top. But if 02148 * flag contains INS_ABOVE_FLOOR_ONLY, once we find the last 02149 * floor, we want to insert above that and no further. 02150 * Also, if there are spell objects on this space, we stop processing 02151 * once we get to them. This reduces the need to traverse over all of 02152 * them when adding another one - this saves quite a bit of cpu time 02153 * when lots of spells are cast in one area. Currently, it is presumed 02154 * that flying non pickable objects are spell objects. 02155 */ 02156 02157 while (top != NULL) { 02158 if (QUERY_FLAG(top, FLAG_IS_FLOOR) 02159 || QUERY_FLAG(top, FLAG_OVERLAY_FLOOR)) 02160 floor = top; 02161 02162 if (QUERY_FLAG(top, FLAG_NO_PICK) 02163 && (top->move_type&(MOVE_FLY_LOW|MOVE_FLY_HIGH)) 02164 && !QUERY_FLAG(top, FLAG_IS_FLOOR)) { 02165 /* We insert above top, so we want this object below this */ 02166 top = top->below; 02167 break; 02168 } 02169 last = top; 02170 top = top->above; 02171 } 02172 /* Don't want top to be NULL, so set it to the last valid object */ 02173 top = last; 02174 02175 /* We let update_position deal with figuring out what the space 02176 * looks like instead of lots of conditions here. 02177 * makes things faster, and effectively the same result. 02178 */ 02179 02180 } /* If objects on this space */ 02181 if (flag&INS_MAP_LOAD) 02182 top = GET_MAP_TOP(op->map, op->x, op->y); 02183 if (flag&INS_ABOVE_FLOOR_ONLY) 02184 top = floor; 02185 02186 /* Top is the object that our object (op) is going to get inserted above. */ 02187 02188 /* First object on this space */ 02189 if (!top) { 02190 op->above = GET_MAP_OB(op->map, op->x, op->y); 02191 if (op->above) 02192 op->above->below = op; 02193 op->below = NULL; 02194 SET_MAP_OB(op->map, op->x, op->y, op); 02195 } else { /* get inserted into the stack above top */ 02196 op->above = top->above; 02197 if (op->above) 02198 op->above->below = op; 02199 op->below = top; 02200 top->above = op; 02201 } 02202 if (op->above == NULL) 02203 SET_MAP_TOP(op->map, op->x, op->y, op); 02204 } /* else not INS_BELOW_ORIGINATOR */ 02205 02206 if (op->type == PLAYER) 02207 op->contr->do_los = 1; 02208 02209 /* If we have a floor, we know the player, if any, will be above 02210 * it, so save a few ticks and start from there. 02211 */ 02212 if (!(flag&INS_MAP_LOAD)) 02213 for (tmp = floor ? floor : GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) { 02214 if (tmp->type == PLAYER) 02215 tmp->contr->socket.update_look = 1; 02216 } 02217 02218 /* If this object glows, it may affect lighting conditions that are 02219 * visible to others on this map. But update_all_los is really 02220 * an inefficient way to do this, as it means los for all players 02221 * on the map will get recalculated. The players could very well 02222 * be far away from this change and not affected in any way - 02223 * this should get redone to only look for players within range, 02224 * or just updating the P_NEED_UPDATE for spaces within this area 02225 * of effect may be sufficient. 02226 */ 02227 if (MAP_DARKNESS(op->map) && (op->glow_radius != 0)) 02228 update_all_los(op->map, op->x, op->y); 02229 02230 02231 /* updates flags (blocked, alive, no magic, etc) for this map space */ 02232 update_object(op, UP_OBJ_INSERT); 02233 02234 if (op->contr && !op->contr->hidden) 02235 op->map->players++; 02236 02237 /* Don't know if moving this to the end will break anything. However, 02238 * we want to have update_look set above before calling this. 02239 * 02240 * check_move_on() must be after this because code called from 02241 * check_move_on() depends on correct map flags (so functions like 02242 * blocked() and wall() work properly), and these flags are updated by 02243 * update_object(). 02244 */ 02245 02246 /* if this is not the head or flag has been passed, don't check walk on status */ 02247 02248 if (!(flag&INS_NO_WALK_ON) && !op->head) { 02249 if (check_move_on(op, originator)) 02250 return NULL; 02251 02252 /* If we are a multi part object, lets work our way through the check 02253 * walk on's. 02254 */ 02255 for (tmp = op->more; tmp != NULL; tmp = tmp->more) 02256 if (check_move_on(tmp, originator)) 02257 return NULL; 02258 } 02259 return op; 02260 } 02261 02271 void replace_insert_ob_in_map(const char *arch_string, object *op) { 02272 object *tmp; 02273 object *tmp1; 02274 02275 /* first search for itself and remove any old instances */ 02276 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp1) { 02277 tmp1 = tmp->above; 02278 if (!strcmp(tmp->arch->name, arch_string)) { /* same archetype */ 02279 remove_ob(tmp); 02280 free_object(tmp); 02281 } 02282 } 02283 02284 tmp1 = arch_to_object(find_archetype(arch_string)); 02285 02286 tmp1->x = op->x; 02287 tmp1->y = op->y; 02288 insert_ob_in_map(tmp1, op->map, op, INS_BELOW_ORIGINATOR); 02289 } 02290 02313 object *get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size) { 02314 object *newob; 02315 02316 if (orig_ob->nrof < nr) { 02317 /* If err is set, the caller knows that nr can be wrong (player trying to drop items), thus don't log that. */ 02318 if (err) 02319 snprintf(err, size, "There are only %u %ss.", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name); 02320 else 02321 LOG(llevDebug, "There are only %u %ss.\n", orig_ob->nrof ? orig_ob->nrof : 1, orig_ob->name); 02322 return NULL; 02323 } 02324 newob = object_create_clone(orig_ob); 02325 newob->nrof = nr; 02326 decrease_ob_nr(orig_ob, nr); 02327 02328 return newob; 02329 } 02330 02345 object *decrease_ob_nr(object *op, uint32 i) { 02346 object *tmp; 02347 player *pl; 02348 02349 if (i == 0) /* objects with op->nrof require this check */ 02350 return op; 02351 02352 if (i > op->nrof) 02353 i = op->nrof; 02354 02355 if (QUERY_FLAG(op, FLAG_REMOVED)) { 02356 op->nrof -= i; 02357 } else if (op->env != NULL) { 02358 /* is this object in the players inventory, or sub container 02359 * therein? 02360 */ 02361 tmp = get_player_container(op->env); 02362 /* nope. Is this a container the player has opened? 02363 * If so, set tmp to that player. 02364 * IMO, searching through all the players will mostly 02365 * likely be quicker than following op->env to the map, 02366 * and then searching the map for a player. 02367 */ 02368 if (!tmp) { 02369 for (pl = first_player; pl; pl = pl->next) 02370 if (pl->ob->container == op->env) 02371 break; 02372 if (pl) 02373 tmp = pl->ob; 02374 else 02375 tmp = NULL; 02376 } 02377 02378 if (i < op->nrof) { 02379 sub_weight(op->env, op->weight*i); 02380 op->nrof -= i; 02381 if (tmp) { 02382 esrv_update_item(UPD_NROF, tmp, op); 02383 } 02384 } else { 02385 remove_ob(op); 02386 op->nrof = 0; 02387 } 02388 } else { 02389 /* On a map. */ 02390 if (i < op->nrof) { 02391 object *pl; 02392 op->nrof -= i; 02393 02394 pl = GET_MAP_OB(op->map, op->x, op->y); 02395 while (pl && !pl->contr) 02396 pl = pl->above; 02397 if (pl && pl->contr) 02398 pl->contr->socket.update_look = 1; 02399 } else { 02400 remove_ob(op); 02401 op->nrof = 0; 02402 } 02403 } 02404 02405 if (op->nrof) { 02406 return op; 02407 } else { 02408 free_object(op); 02409 return NULL; 02410 } 02411 } 02412 02423 static void increase_ob_nr(object *op, uint32 i) { 02424 object *tmp; 02425 player *pl; 02426 02427 if (i == 0) /* objects with op->nrof require this check */ 02428 return; 02429 02430 if (QUERY_FLAG(op, FLAG_REMOVED)) { 02431 op->nrof += i; 02432 } else if (op->env != NULL) { 02433 /* is this object in the players inventory, or sub container 02434 * therein? 02435 */ 02436 tmp = get_player_container(op->env); 02437 /* nope. Is this a container the player has opened? 02438 * If so, set tmp to that player. 02439 * IMO, searching through all the players will mostly 02440 * likely be quicker than following op->env to the map, 02441 * and then searching the map for a player. 02442 */ 02443 if (!tmp) { 02444 for (pl = first_player; pl; pl = pl->next) 02445 if (pl->ob->container == op->env) 02446 break; 02447 if (pl) 02448 tmp = pl->ob; 02449 else 02450 tmp = NULL; 02451 } 02452 02453 add_weight(op->env, op->weight*i); 02454 op->nrof += i; 02455 if (tmp) { 02456 esrv_update_item(UPD_NROF, tmp, op); 02457 } 02458 } else { 02459 /* On a map. */ 02460 object *pl; 02461 02462 op->nrof += i; 02463 02464 pl = GET_MAP_OB(op->map, op->x, op->y); 02465 while (pl && !pl->contr) 02466 pl = pl->above; 02467 if (pl && pl->contr) 02468 pl->contr->socket.update_look = 1; 02469 } 02470 } 02471 02486 void add_weight(object *op, signed long weight) { 02487 while (op != NULL) { 02488 if (op->type == CONTAINER) { 02489 weight = (signed long)(weight*(100-op->stats.Str)/100); 02490 } 02491 op->carrying += weight; 02492 op = op->env; 02493 } 02494 } 02495 02510 object *insert_ob_in_ob(object *op, object *where) { 02511 object *tmp, *otmp; 02512 02513 if (!QUERY_FLAG(op, FLAG_REMOVED)) { 02514 StringBuffer *sb; 02515 char *diff; 02516 02517 sb = stringbuffer_new(); 02518 dump_object(op, sb); 02519 diff = stringbuffer_finish(sb); 02520 LOG(llevError, "Trying to insert (ob) inserted object.\n%s\n", diff); 02521 free(diff); 02522 return op; 02523 } 02524 02525 if (where == NULL) { 02526 StringBuffer *sb; 02527 char *diff; 02528 02529 sb = stringbuffer_new(); 02530 dump_object(op, sb); 02531 diff = stringbuffer_finish(sb); 02532 LOG(llevError, "Trying to put object in NULL.\n%s\n", diff); 02533 free(diff); 02534 return op; 02535 } 02536 if (where->head) { 02537 LOG(llevDebug, "Warning: Tried to insert object wrong part of multipart object.\n"); 02538 where = where->head; 02539 } 02540 if (op->more) { 02541 LOG(llevError, "Tried to insert multipart object %s (%d)\n", op->name, op->count); 02542 return op; 02543 } 02544 CLEAR_FLAG(op, FLAG_OBJ_ORIGINAL); 02545 CLEAR_FLAG(op, FLAG_REMOVED); 02546 if (op->nrof) { 02547 for (tmp = where->inv; tmp != NULL; tmp = tmp->below) 02548 if (can_merge(tmp, op)) { 02549 /* return the original object and remove inserted object 02550 * (client needs the original object) */ 02551 increase_ob_nr(tmp, op->nrof); 02552 SET_FLAG(op, FLAG_REMOVED); 02553 free_object(op); /* free the inserted object */ 02554 return tmp; 02555 } 02556 02557 /* the item couldn't merge. */ 02558 add_weight(where, op->weight*op->nrof); 02559 } else 02560 add_weight(where, (op->weight+op->carrying)); 02561 02562 op->map = NULL; 02563 op->env = where; 02564 op->above = NULL; 02565 op->below = NULL; 02566 op->x = 0, 02567 op->y = 0; 02568 op->ox = 0, 02569 op->oy = 0; 02570 02571 /* Client has no idea of ordering so lets not bother ordering it here. 02572 * It sure simplifies this function... 02573 */ 02574 if (where->inv == NULL) 02575 where->inv = op; 02576 else { 02577 op->below = where->inv; 02578 op->below->above = op; 02579 where->inv = op; 02580 } 02581 02582 /* Update in 2 cases: object goes into player's inventory, or object goes into container the player 02583 * is looking into. */ 02584 if (where->contr != NULL) 02585 esrv_send_item(where, op); 02586 else if (where->type == CONTAINER && QUERY_FLAG(where, FLAG_APPLIED)) { 02587 object *pl = NULL; 02588 02589 if (op->env->env && op->env->env->contr) 02590 /* Container is in player's inventory. */ 02591 pl = op->env->env; 02592 else if (op->env->map) { 02593 /* Container on map, look above for player. */ 02594 object *above = op->env->above; 02595 02596 while (above && !above->contr) 02597 above = above->above; 02598 if (above) 02599 pl = above; 02600 } 02601 if (pl) 02602 esrv_send_item(pl, op); 02603 } 02604 02605 otmp = get_player_container(where); 02606 if (otmp && otmp->contr != NULL) { 02607 if (!QUERY_FLAG(otmp, FLAG_NO_FIX_PLAYER) 02608 && (QUERY_FLAG(op, FLAG_APPLIED) || (op->type == SKILL) || (op->glow_radius != 0))) 02609 /* fix_object will only consider applied items, or skills, or items with a glow radius. 02610 thus no need to call it if our object hasn't that. */ 02611 fix_object(otmp); 02612 } 02613 02614 /* reset the light list and los of the players on the map */ 02615 if ((op->glow_radius != 0) && where->map) { 02616 #ifdef DEBUG_LIGHTS 02617 LOG(llevDebug, " insert_ob_in_ob(): got %s to insert in map/op\n", op->name); 02618 #endif /* DEBUG_LIGHTS */ 02619 if (MAP_DARKNESS(where->map)) { 02620 SET_MAP_FLAGS(where->map, where->x, where->y, P_NEED_UPDATE); 02621 update_position(where->map, where->x, where->y); 02622 update_all_los(where->map, where->x, where->y); 02623 } 02624 } 02625 02626 return op; 02627 } 02628 02651 int check_move_on(object *op, object *originator) { 02652 object *tmp; 02653 tag_t tag; 02654 mapstruct *m = op->map; 02655 int x = op->x, y = op->y; 02656 MoveType move_on, move_slow, move_block; 02657 02658 if (QUERY_FLAG(op, FLAG_NO_APPLY)) 02659 return 0; 02660 02661 tag = op->count; 02662 02663 move_on = GET_MAP_MOVE_ON(op->map, op->x, op->y); 02664 move_slow = GET_MAP_MOVE_SLOW(op->map, op->x, op->y); 02665 move_block = GET_MAP_MOVE_BLOCK(op->map, op->x, op->y); 02666 02667 /* if nothing on this space will slow op down or be applied, 02668 * no need to do checking below. have to make sure move_type 02669 * is set, as lots of objects don't have it set - we treat that 02670 * as walking. 02671 */ 02672 if (op->move_type 02673 && !(op->move_type&move_on) 02674 && !(op->move_type&move_slow)) 02675 return 0; 02676 02677 /* This is basically inverse logic of that below - basically, 02678 * if the object can avoid the move on or slow move, they do so, 02679 * but can't do it if the alternate movement they are using is 02680 * blocked. Logic on this seems confusing, but does seem correct. 02681 */ 02682 if ((op->move_type&~move_on&~move_block) != 0 02683 && (op->move_type&~move_slow&~move_block) != 0) 02684 return 0; 02685 02686 /* The objects have to be checked from top to bottom. 02687 * Hence, we first go to the top: 02688 */ 02689 02690 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) { 02691 /* Trim the search when we find the first other spell effect 02692 * this helps performance so that if a space has 50 spell objects, 02693 * we don't need to check all of them. 02694 */ 02695 if ((tmp->move_type&MOVE_FLY_LOW) && QUERY_FLAG(tmp, FLAG_NO_PICK)) 02696 break; 02697 } 02698 for (; tmp != NULL; tmp = tmp->below) { 02699 if (tmp == op) 02700 continue; /* Can't apply yourself */ 02701 02702 /* Check to see if one of the movement types should be slowed down. 02703 * Second check makes sure that the movement types not being slowed 02704 * (~slow_move) is not blocked on this space - just because the 02705 * space doesn't slow down swimming (for example), if you can't actually 02706 * swim on that space, can't use it to avoid the penalty. 02707 */ 02708 if (!QUERY_FLAG(op, FLAG_WIZPASS)) { 02709 if ((!op->move_type && tmp->move_slow&MOVE_WALK) 02710 || ((op->move_type&tmp->move_slow) && (op->move_type&~tmp->move_slow&~tmp->move_block) == 0)) { 02711 float diff; 02712 02713 diff = tmp->move_slow_penalty*FABS(op->speed); 02714 if (op->type == PLAYER) { 02715 if ((QUERY_FLAG(tmp, FLAG_IS_HILLY) && find_skill_by_number(op, SK_CLIMBING)) 02716 || (QUERY_FLAG(tmp, FLAG_IS_WOODED) && find_skill_by_number(op, SK_WOODSMAN))) { 02717 diff /= 4.0; 02718 } 02719 } 02720 op->speed_left -= diff; 02721 } 02722 } 02723 02724 /* Basically same logic as above, except now for actual apply. */ 02725 if ((!op->move_type && tmp->move_on&MOVE_WALK) 02726 || ((op->move_type&tmp->move_on) && (op->move_type&~tmp->move_on&~tmp->move_block) == 0)) { 02727 02728 ob_move_on(tmp, op, originator); 02729 if (was_destroyed(op, tag)) 02730 return 1; 02731 02732 /* what the person/creature stepped onto has moved the object 02733 * someplace new. Don't process any further - if we did, 02734 * have a feeling strange problems would result. 02735 */ 02736 if (op->map != m || op->x != x || op->y != y) 02737 return 0; 02738 } 02739 } 02740 return 0; 02741 } 02742 02755 object *present_arch(const archetype *at, mapstruct *m, int x, int y) { 02756 object *tmp; 02757 02758 if (m == NULL || out_of_map(m, x, y)) { 02759 LOG(llevError, "Present_arch called outside map.\n"); 02760 return NULL; 02761 } 02762 02763 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) 02764 if (tmp->arch == at) 02765 return tmp; 02766 return NULL; 02767 } 02768 02782 object *present(uint8 type, mapstruct *m, int x, int y) { 02783 object *tmp; 02784 02785 if (out_of_map(m, x, y)) { 02786 LOG(llevError, "Present called outside map.\n"); 02787 return NULL; 02788 } 02789 02790 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) 02791 if (tmp->type == type) 02792 return tmp; 02793 return NULL; 02794 } 02795 02806 object *present_in_ob(uint8 type, const object *op) { 02807 object *tmp; 02808 02809 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) 02810 if (tmp->type == type) 02811 return tmp; 02812 return NULL; 02813 } 02814 02840 object *present_in_ob_by_name(int type, const char *str, const object *op) { 02841 object *tmp; 02842 02843 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) { 02844 if ((type == -1 || tmp->type == type) && (!strcmp(str, tmp->name))) 02845 return tmp; 02846 } 02847 return NULL; 02848 } 02849 02859 object *present_arch_in_ob(const archetype *at, const object *op) { 02860 object *tmp; 02861 02862 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) 02863 if (tmp->arch == at) 02864 return tmp; 02865 return NULL; 02866 } 02867 02876 void flag_inv(object*op, int flag) { 02877 object *tmp; 02878 02879 if (op->inv) 02880 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) { 02881 SET_FLAG(tmp, flag); 02882 flag_inv(tmp, flag); 02883 } 02884 } 02885 02894 void unflag_inv(object*op, int flag) { 02895 object *tmp; 02896 02897 if (op->inv) 02898 for (tmp = op->inv; tmp != NULL; tmp = tmp->below) { 02899 CLEAR_FLAG(tmp, flag); 02900 unflag_inv(tmp, flag); 02901 } 02902 } 02903 02913 void set_cheat(object *op) { 02914 SET_FLAG(op, FLAG_WAS_WIZ); 02915 flag_inv(op, FLAG_WAS_WIZ); 02916 } 02917 02935 int find_multi_free_spot_around(object *ob, object *gen, int *hx, int *hy) { 02936 int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag; 02937 int freecount = 0; 02938 02939 if (ob->head) 02940 ob = ob->head; 02941 02942 get_multi_size(ob, &sx, &sy, &sx2, &sy2); 02943 get_multi_size(gen, &genx, &geny, &genx2, &geny2); 02944 /* 02945 * sx and sy are now the coords of the bottom right corner of ob relative to the head. 02946 * genx and geny are now the coords of the bottom right corner of gen relative to the head. 02947 * sx2 and sy2 are now the coords of the head of ob relative to the top left corner. 02948 * genx2 and geny2 are now the coords of the head of gen relative to the top left corner. 02949 */ 02950 02951 sx++; 02952 sy++; 02953 genx++; 02954 geny++; 02955 /* 02956 * sx, sy, genx, and geny, are now the size of the object, excluding parts left and above 02957 * the head. 02958 */ 02959 02960 ix = gen->x-sx-genx2; 02961 iy = gen->y-sy-geny2; 02962 sx += genx+sx2; 02963 sy += geny+sy2; 02964 /* 02965 * ix and iy are the map coords of the top left square where the head of ob could possibly 02966 * be placed. sx and sy are now the size of the square to search for placement of the head 02967 * relative to ix and iy. 02968 */ 02969 02970 /* 02971 * Loop around the square of possible positions for the head of ob object: 02972 */ 02973 for (i = 0; i < (sx+sx+sy+sy); i++) { 02974 if (i <= sx) { 02975 nx = i+ix; 02976 ny = iy; 02977 } else if (i <= (sx+sy)) { 02978 nx = ix+sx; 02979 ny = iy+i-sx; 02980 } else if (i <= (sx+sy+sx)) { 02981 nx = ix+sx-(i-(sx+sy)); 02982 ny = iy+sy; 02983 } else { 02984 nx = ix; 02985 ny = iy+sy-(i-(sx+sy+sx)); 02986 } 02987 /* Check if the spot is free. */ 02988 flag = ob_blocked(ob, gen->map, nx, ny); 02989 if (!flag) { 02990 freecount++; 02991 } 02992 } 02993 /* If no free spaces, return. */ 02994 if (!freecount) 02995 return -1; 02996 02997 /* Choose a random valid position */ 02998 freecount = RANDOM()%freecount; 02999 for (i = 0; i < (sx+sx+sy+sy); i++) { 03000 if (i <= sx) { 03001 nx = i+ix; 03002 ny = iy; 03003 } else if (i <= (sx+sy)) { 03004 nx = ix+sx; 03005 ny = iy+i-sx; 03006 } else if (i <= (sx+sy+sx)) { 03007 nx = ix+sx-(i-(sx+sy)); 03008 ny = iy+sy; 03009 } else { 03010 nx = ix; 03011 ny = iy+sy-(i-(sx+sy+sx)); 03012 } 03013 03014 /* Make sure it's within map. */ 03015 if (nx < 0 || nx >= MAP_WIDTH(gen->map) 03016 || ny < 0 || ny >= MAP_HEIGHT(gen->map)) 03017 continue; 03018 03019 /* Check if the spot is free.*/ 03020 flag = ob_blocked(ob, gen->map, nx, ny); 03021 if (!flag) { 03022 freecount--; 03023 if (freecount <= 0) { 03024 *hx = nx; 03025 *hy = ny; 03026 return 0; 03027 } 03028 } 03029 } 03030 return -1; 03031 } 03032 03052 int find_multi_free_spot_within_radius(object *ob, object *gen, int *hx, int *hy) { 03053 int genx, geny, genx2, geny2, sx, sy, sx2, sy2, ix, iy, nx, ny, i, flag; 03054 sint8 x, y, radius; 03055 int freecount = 0, freecountstop = 0; 03056 const char *value; 03057 sint8 *x_array; 03058 sint8 *y_array; 03059 03060 /* If radius is not set, default to 1 */ 03061 value = get_ob_key_value(gen, "generator_radius"); 03062 if (value) { 03063 radius = (sint8)strtol((char *)value, NULL, 10); 03064 if (radius < 1) { 03065 radius = 1; 03066 } 03067 } else { 03068 radius = 1; 03069 } 03070 03071 if (ob->head) 03072 ob = ob->head; 03073 03074 get_multi_size(ob, &sx, &sy, &sx2, &sy2); 03075 get_multi_size(gen, &genx, &geny, &genx2, &geny2); 03076 /* 03077 * sx and sy are now the coords of the bottom right corner 03078 * of ob relative to the head. 03079 * genx and geny are now the coords of the bottom right corner 03080 * of gen relative to the head. 03081 * sx2 and sy2 are now the coords of the head of ob relative 03082 * to the top left corner. 03083 * genx2 and geny2 are now the coords of the head of gen relative 03084 * to the top left corner. 03085 */ 03086 03087 sx++; 03088 sy++; 03089 genx++; 03090 geny++; 03091 /* 03092 * sx, sy, genx, and geny, are now the size of the object, 03093 * excluding parts left and above the head. 03094 */ 03095 03096 ix = gen->x-sx-genx2-radius+1; 03097 iy = gen->y-sy-geny2-radius+1; 03098 sx += genx+sx2+radius*2-1; 03099 sy += geny+sy2+radius*2-1; 03100 03101 /* 03102 * ix and iy are the map coords of the top left square where 03103 * the head of ob could possibly be placed. sx and sy are now 03104 * the size of the square to search for placement of the head 03105 * relative to ix and iy. 03106 */ 03107 03108 /* Create arrays large enough to hold free space coordinates */ 03109 x_array = malloc(sx*sy*sizeof(sint8)); 03110 y_array = malloc(sx*sy*sizeof(sint8)); 03111 03112 /* 03113 * Loop through the area of possible positions for the head of ob object: 03114 */ 03115 for (x = 0; x < sx; x++) { 03116 for (y = 0; y < sy; y++) { 03117 nx = ix+x; 03118 ny = iy+y; 03119 03120 03121 /* Make sure it's within map. */ 03122 if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) { 03123 continue; 03124 } 03125 03126 /* Check if the spot is free. */ 03127 flag = ob_blocked(ob, gen->map, nx, ny); 03128 if (!flag) { 03129 x_array[freecount] = nx; 03130 y_array[freecount] = ny; 03131 freecount++; 03132 } 03133 } 03134 } 03135 /* If no free spaces, return. */ 03136 if (!freecount) { 03137 free(x_array); 03138 free(y_array); 03139 return -1; 03140 } 03141 03142 /* Choose a random valid position */ 03143 freecountstop = RANDOM()%freecount; 03144 for (i = 0; i < freecount; i++) { 03145 nx = x_array[i]; 03146 ny = y_array[i]; 03147 03148 /* Check if the spot is free.*/ 03149 flag = ob_blocked(ob, gen->map, nx, ny); 03150 if (!flag) { 03151 freecountstop--; 03152 if (freecountstop <= 0) { 03153 *hx = nx; 03154 *hy = ny; 03155 free(x_array); 03156 free(y_array); 03157 return 0; 03158 } 03159 } 03160 } 03161 free(x_array); 03162 free(y_array); 03163 return -1; 03164 } 03165 03200 int find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop) { 03201 int i, index = 0, flag; 03202 static int altern[SIZEOFFREE]; 03203 03204 for (i = start; i < stop; i++) { 03205 flag = ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i]); 03206 if (!flag) 03207 altern[index++] = i; 03208 03209 /* Basically, if we find a wall on a space, we cut down the search size. 03210 * In this way, we won't return spaces that are on another side of a wall. 03211 * This mostly work, but it cuts down the search size in all directions - 03212 * if the space being examined only has a wall to the north and empty 03213 * spaces in all the other directions, this will reduce the search space 03214 * to only the spaces immediately surrounding the target area, and 03215 * won't look 2 spaces south of the target space. 03216 */ 03217 else if ((flag&AB_NO_PASS) && maxfree[i] < stop) 03218 stop = maxfree[i]; 03219 } 03220 if (!index) 03221 return -1; 03222 return altern[RANDOM()%index]; 03223 } 03224 03240 int find_first_free_spot(const object *ob, mapstruct *m, int x, int y) { 03241 int i; 03242 03243 for (i = 0; i < SIZEOFFREE; i++) { 03244 if (!ob_blocked(ob, m, x+freearr_x[i], y+freearr_y[i])) 03245 return i; 03246 } 03247 return -1; 03248 } 03249 03259 static void permute(int *arr, int begin, int end) { 03260 int i, j, tmp, len; 03261 03262 len = end-begin; 03263 for (i = begin; i < end; i++) { 03264 j = begin+RANDOM()%len; 03265 03266 tmp = arr[i]; 03267 arr[i] = arr[j]; 03268 arr[j] = tmp; 03269 } 03270 } 03271 03283 void get_search_arr(int *search_arr) { 03284 int i; 03285 03286 for (i = 0; i < SIZEOFFREE; i++) { 03287 search_arr[i] = i; 03288 } 03289 03290 permute(search_arr, 1, SIZEOFFREE1+1); 03291 permute(search_arr, SIZEOFFREE1+1, SIZEOFFREE2+1); 03292 permute(search_arr, SIZEOFFREE2+1, SIZEOFFREE); 03293 } 03294 03313 int find_dir(mapstruct *m, int x, int y, object *exclude) { 03314 int i, max = SIZEOFFREE, mflags; 03315 sint16 nx, ny; 03316 object *tmp; 03317 mapstruct *mp; 03318 MoveType blocked, move_type; 03319 03320 if (exclude && exclude->head) { 03321 exclude = exclude->head; 03322 move_type = exclude->move_type; 03323 } else { 03324 /* If we don't have anything, presume it can use all movement types. */ 03325 move_type = MOVE_ALL; 03326 } 03327 03328 for (i = 1; i < max; i++) { 03329 mp = m; 03330 nx = x+freearr_x[i]; 03331 ny = y+freearr_y[i]; 03332 03333 mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny); 03334 if (mflags&P_OUT_OF_MAP) { 03335 max = maxfree[i]; 03336 } else { 03337 blocked = GET_MAP_MOVE_BLOCK(mp, nx, ny); 03338 03339 if ((move_type&blocked) == move_type) { 03340 max = maxfree[i]; 03341 } else if (mflags&P_IS_ALIVE) { 03342 for (tmp = GET_MAP_OB(mp, nx, ny); tmp != NULL; tmp = tmp->above) { 03343 if ((QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER) 03344 && (tmp != exclude ||(tmp->head && tmp->head != exclude))) { 03345 break; 03346 } 03347 } 03348 if (tmp) { 03349 return freedir[i]; 03350 } 03351 } 03352 } 03353 } 03354 return 0; 03355 } 03356 03364 int distance(const object *ob1, const object *ob2) { 03365 int i; 03366 03367 i = (ob1->x-ob2->x)*(ob1->x-ob2->x)+ 03368 (ob1->y-ob2->y)*(ob1->y-ob2->y); 03369 return i; 03370 } 03371 03380 int find_dir_2(int x, int y) { 03381 int q; 03382 03383 if (!y) 03384 q = -300*x; 03385 else 03386 q = x*100/y; 03387 if (y > 0) { 03388 if (q < -242) 03389 return 3; 03390 if (q < -41) 03391 return 2; 03392 if (q < 41) 03393 return 1; 03394 if (q < 242) 03395 return 8; 03396 return 7; 03397 } 03398 if (q < -242) 03399 return 7; 03400 if (q < -41) 03401 return 6; 03402 if (q < 41) 03403 return 5; 03404 if (q < 242) 03405 return 4; 03406 return 3; 03407 } 03408 03417 int absdir(int d) { 03418 while (d < 1) 03419 d += 8; 03420 while (d > 8) 03421 d -= 8; 03422 return d; 03423 } 03424 03434 int dirdiff(int dir1, int dir2) { 03435 int d; 03436 03437 d = abs(dir1-dir2); 03438 if (d > 4) 03439 d = 8-d; 03440 return d; 03441 } 03442 03454 static const int reduction_dir[SIZEOFFREE][3] = { 03455 { 0, 0, 0 }, /* 0 */ 03456 { 0, 0, 0 }, /* 1 */ 03457 { 0, 0, 0 }, /* 2 */ 03458 { 0, 0, 0 }, /* 3 */ 03459 { 0, 0, 0 }, /* 4 */ 03460 { 0, 0, 0 }, /* 5 */ 03461 { 0, 0, 0 }, /* 6 */ 03462 { 0, 0, 0 }, /* 7 */ 03463 { 0, 0, 0 }, /* 8 */ 03464 { 8, 1, 2 }, /* 9 */ 03465 { 1, 2, -1 }, /* 10 */ 03466 { 2, 10, 12 }, /* 11 */ 03467 { 2, 3, -1 }, /* 12 */ 03468 { 2, 3, 4 }, /* 13 */ 03469 { 3, 4, -1 }, /* 14 */ 03470 { 4, 14, 16 }, /* 15 */ 03471 { 5, 4, -1 }, /* 16 */ 03472 { 4, 5, 6 }, /* 17 */ 03473 { 6, 5, -1 }, /* 18 */ 03474 { 6, 20, 18 }, /* 19 */ 03475 { 7, 6, -1 }, /* 20 */ 03476 { 6, 7, 8 }, /* 21 */ 03477 { 7, 8, -1 }, /* 22 */ 03478 { 8, 22, 24 }, /* 23 */ 03479 { 8, 1, -1 }, /* 24 */ 03480 { 24, 9, 10 }, /* 25 */ 03481 { 9, 10, -1 }, /* 26 */ 03482 { 10, 11, -1 }, /* 27 */ 03483 { 27, 11, 29 }, /* 28 */ 03484 { 11, 12, -1 }, /* 29 */ 03485 { 12, 13, -1 }, /* 30 */ 03486 { 12, 13, 14 }, /* 31 */ 03487 { 13, 14, -1 }, /* 32 */ 03488 { 14, 15, -1 }, /* 33 */ 03489 { 33, 15, 35 }, /* 34 */ 03490 { 16, 15, -1 }, /* 35 */ 03491 { 17, 16, -1 }, /* 36 */ 03492 { 18, 17, 16 }, /* 37 */ 03493 { 18, 17, -1 }, /* 38 */ 03494 { 18, 19, -1 }, /* 39 */ 03495 { 41, 19, 39 }, /* 40 */ 03496 { 19, 20, -1 }, /* 41 */ 03497 { 20, 21, -1 }, /* 42 */ 03498 { 20, 21, 22 }, /* 43 */ 03499 { 21, 22, -1 }, /* 44 */ 03500 { 23, 22, -1 }, /* 45 */ 03501 { 45, 47, 23 }, /* 46 */ 03502 { 23, 24, -1 }, /* 47 */ 03503 { 24, 9, -1 } /* 48 */ 03504 }; 03505 03524 int can_see_monsterP(mapstruct *m, int x, int y, int dir) { 03525 sint16 dx, dy; 03526 int mflags; 03527 03528 if (dir < 0) 03529 return 0; /* exit condition: invalid direction */ 03530 03531 dx = x+freearr_x[dir]; 03532 dy = y+freearr_y[dir]; 03533 03534 mflags = get_map_flags(m, &m, dx, dy, &dx, &dy); 03535 03536 /* This functional arguably was incorrect before - it was 03537 * checking for P_WALL - that was basically seeing if 03538 * we could move to the monster - this is being more 03539 * literal on if we can see it. To know if we can actually 03540 * move to the monster, we'd need the monster passed in or 03541 * at least its move type. 03542 */ 03543 if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW)) 03544 return 0; 03545 03546 /* yes, can see. */ 03547 if (dir < 9) 03548 return 1; 03549 return can_see_monsterP(m, x, y, reduction_dir[dir][0])| 03550 can_see_monsterP(m, x, y, reduction_dir[dir][1])| 03551 can_see_monsterP(m, x, y, reduction_dir[dir][2]); 03552 } 03553 03569 int can_pick(const object *who, const object *item) { 03570 /* I re-wrote this as a series of if statements 03571 * instead of a nested return (foo & bar && yaz) 03572 * - I think this is much more readable, 03573 * and likely compiler effectively optimizes it the 03574 * same. 03575 */ 03576 if (item->weight <= 0) 03577 return 0; 03578 if (QUERY_FLAG(item, FLAG_NO_PICK)) 03579 return 0; 03580 if (QUERY_FLAG(item, FLAG_ALIVE)) 03581 return 0; 03582 if (item->invisible) 03583 return 0; 03584 03585 /* Weight limit for monsters */ 03586 if (who->type != PLAYER && item->weight > (who->weight/3)) 03587 return 0; 03588 03589 /* Can not pick up multipart objects */ 03590 if (item->head || item->more) 03591 return 0; 03592 03593 /* Everything passes, so OK to pick up */ 03594 return 1; 03595 } 03596 03608 object *object_create_clone(object *asrc) { 03609 object *dst = NULL, *tmp, *src, *part, *prev, *item; 03610 03611 if (!asrc) 03612 return NULL; 03613 src = asrc; 03614 if (src->head) 03615 src = src->head; 03616 03617 prev = NULL; 03618 for (part = src; part; part = part->more) { 03619 tmp = get_object(); 03620 copy_object(part, tmp); 03621 tmp->x -= src->x; 03622 tmp->y -= src->y; 03623 if (!part->head) { 03624 dst = tmp; 03625 tmp->head = NULL; 03626 } else { 03627 tmp->head = dst; 03628 } 03629 tmp->more = NULL; 03630 if (prev) 03631 prev->more = tmp; 03632 prev = tmp; 03633 } 03634 /*** copy inventory ***/ 03635 for (item = src->inv; item; item = item->below) { 03636 (void)insert_ob_in_ob(object_create_clone(item), dst); 03637 } 03638 03639 return dst; 03640 } 03641 03656 object *find_obj_by_type_subtype(const object *who, int type, int subtype) { 03657 object *tmp; 03658 03659 for (tmp = who->inv; tmp; tmp = tmp->below) 03660 if (tmp->type == type && tmp->subtype == subtype) 03661 return tmp; 03662 03663 return NULL; 03664 } 03665 03676 key_value *get_ob_key_link(const object *ob, const char *key) { 03677 key_value *link; 03678 03679 for (link = ob->key_values; link != NULL; link = link->next) { 03680 if (link->key == key) { 03681 return link; 03682 } 03683 } 03684 03685 return NULL; 03686 } 03687 03701 const char *get_ob_key_value(const object *op, const char *const key) { 03702 key_value *link; 03703 const char *canonical_key; 03704 03705 canonical_key = find_string(key); 03706 03707 if (canonical_key == NULL) { 03708 /* 1. There being a field named key on any object 03709 * implies there'd be a shared string to find. 03710 * 2. Since there isn't, no object has this field. 03711 * 3. Therefore, *this *object doesn't have this field. 03712 */ 03713 return NULL; 03714 } 03715 03716 /* This is copied from get_ob_key_link() above - 03717 * only 4 lines, and saves the function call overhead. 03718 */ 03719 for (link = op->key_values; link != NULL; link = link->next) { 03720 if (link->key == canonical_key) { 03721 return link->value; 03722 } 03723 } 03724 return NULL; 03725 } 03726 03741 static int set_ob_key_value_s(object *op, const char *canonical_key, const char *value, int add_key) { 03742 key_value *field = NULL, *last = NULL; 03743 03744 LOG(llevDebug, "set_ob_value_s: '%s' '%s' %d\n", canonical_key, value ? value : "null", add_key); 03745 03746 for (field = op->key_values; field != NULL; field = field->next) { 03747 if (field->key != canonical_key) { 03748 last = field; 03749 continue; 03750 } 03751 03752 if (field->value) 03753 FREE_AND_CLEAR_STR(field->value); 03754 if (value) 03755 field->value = add_string(value); 03756 else { 03757 /* Basically, if the archetype has this key set, 03758 * we need to store the null value so when we save 03759 * it, we save the empty value so that when we load, 03760 * we get this value back again. 03761 */ 03762 if (get_ob_key_link(&op->arch->clone, canonical_key)) 03763 field->value = NULL; 03764 else { 03765 /* Delete this link */ 03766 if (field->key) 03767 FREE_AND_CLEAR_STR(field->key); 03768 if (field->value) 03769 FREE_AND_CLEAR_STR(field->value); 03770 if (last) 03771 last->next = field->next; 03772 else 03773 op->key_values = field->next; 03774 free(field); 03775 } 03776 } 03777 return TRUE; 03778 } 03779 /* IF we get here, key doesn't exist */ 03780 03781 /* No field, we'll have to add it. */ 03782 03783 if (!add_key) { 03784 return FALSE; 03785 } 03786 /* There isn't any good reason to store a null 03787 * value in the key/value list. If the archetype has 03788 * this key, then we should also have it, so shouldn't 03789 * be here. If user wants to store empty strings, 03790 * should pass in "" 03791 */ 03792 if (value == NULL) 03793 return TRUE; 03794 03795 field = malloc(sizeof(key_value)); 03796 03797 field->key = add_refcount(canonical_key); 03798 field->value = add_string(value); 03799 /* Usual prepend-addition. */ 03800 field->next = op->key_values; 03801 op->key_values = field; 03802 03803 return TRUE; 03804 } 03805 03826 int set_ob_key_value(object *op, const char *key, const char *value, int add_key) { 03827 const char *canonical_key = NULL; 03828 int floating_ref = FALSE; 03829 int ret; 03830 03831 /* HACK This mess is to make sure set_ob_value() passes a shared string 03832 * to get_ob_key_link(), without leaving a leaked refcount. 03833 */ 03834 03835 canonical_key = find_string(key); 03836 if (canonical_key == NULL) { 03837 canonical_key = add_string(key); 03838 floating_ref = TRUE; 03839 } 03840 03841 ret = set_ob_key_value_s(op, canonical_key, value, add_key); 03842 03843 if (floating_ref) { 03844 free_string(canonical_key); 03845 } 03846 03847 return ret; 03848 } 03849 03901 int item_matched_string(object *pl, object *op, const char *name) { 03902 char *cp, local_name[MAX_BUF], name_op[MAX_BUF], name_short[HUGE_BUF], bname_s[MAX_BUF], bname_p[MAX_BUF]; 03903 int count, retval = 0; 03904 strcpy(local_name, name); /* strtok is destructive to name */ 03905 03906 for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) { 03907 while (cp[0] == ' ') 03908 ++cp; /* get rid of spaces */ 03909 03910 /* LOG(llevDebug, "Trying to match %s\n", cp);*/ 03911 /* All is a very generic match - low match value */ 03912 if (!strcmp(cp, "all")) 03913 return 1; 03914 03915 /* unpaid is a little more specific */ 03916 if (!strcmp(cp, "unpaid") && QUERY_FLAG(op, FLAG_UNPAID)) 03917 return 2; 03918 if (!strcmp(cp, "cursed") 03919 && QUERY_FLAG(op, FLAG_KNOWN_CURSED) 03920 && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))) 03921 return 2; 03922 03923 if (!strcmp(cp, "unlocked") && !QUERY_FLAG(op, FLAG_INV_LOCKED)) 03924 return 2; 03925 03926 /* Allow for things like '100 arrows' */ 03927 if ((count = atoi(cp)) != 0) { 03928 cp = strchr(cp, ' '); 03929 while (cp && cp[0] == ' ') 03930 ++cp; /* get rid of spaces */ 03931 } else { 03932 if (pl->type == PLAYER) 03933 count = pl->contr->count; 03934 else 03935 count = 0; 03936 } 03937 03938 if (!cp || cp[0] == '\0' || count < 0) 03939 return 0; 03940 03941 /* The code here should go from highest retval to lowest. That 03942 * is because of the 'else' handling - we don't want to match on 03943 * something and set a low retval, even though it may match a higher retcal 03944 * later. So keep it in descending order here, so we try for the best 03945 * match first, and work downward. 03946 */ 03947 query_name(op, name_op, MAX_BUF); 03948 query_short_name(op, name_short, HUGE_BUF); 03949 query_base_name(op, 0, bname_s, MAX_BUF); 03950 query_base_name(op, 1, bname_p, MAX_BUF); 03951 03952 if (!strcasecmp(cp, name_op)) 03953 retval = 20; 03954 else if (!strcasecmp(cp, name_short)) 03955 retval = 18; 03956 else if (!strcasecmp(cp, bname_s)) 03957 retval = 16; 03958 else if (!strcasecmp(cp, bname_p)) 03959 retval = 16; 03960 else if (op->custom_name && !strcasecmp(cp, op->custom_name)) 03961 retval = 15; 03962 else if (!strncasecmp(cp, bname_s, strlen(cp))) 03963 retval = 14; 03964 else if (!strncasecmp(cp, bname_p, strlen(cp))) 03965 retval = 14; 03966 /* Do substring checks, so things like 'Str+1' will match. 03967 * retval of these should perhaps be lower - they are lower 03968 * then the specific strcasecmp aboves, but still higher than 03969 * some other match criteria. 03970 */ 03971 else if (strstr(bname_p, cp)) 03972 retval = 12; 03973 else if (strstr(bname_s, cp)) 03974 retval = 12; 03975 else if (strstr(name_short, cp)) 03976 retval = 12; 03977 /* Check against plural/non plural based on count. */ 03978 else if (count > 1 && !strcasecmp(cp, op->name_pl)) { 03979 retval = 6; 03980 } else if (count == 1 && !strcasecmp(op->name, cp)) { 03981 retval = 6; 03982 } 03983 /* base name matched - not bad */ 03984 else if (strcasecmp(cp, op->name) == 0 && !count) 03985 retval = 4; 03986 /* Check for partial custom name, but give a real low priority */ 03987 else if (op->custom_name && strstr(op->custom_name, cp)) 03988 retval = 3; 03989 03990 if (retval) { 03991 if (pl->type == PLAYER) 03992 pl->contr->count = count; 03993 return retval; 03994 } 03995 } 03996 return 0; 03997 } 03998 04007 void fix_multipart_object(object *tmp) { 04008 archetype *at; 04009 object *op, *last; 04010 04011 if (!tmp->map) { 04012 LOG(llevError, "fix_multipart_object: not on a map!\n"); 04013 return; 04014 } 04015 04016 /* already multipart - don't do anything more */ 04017 if (tmp->head || tmp->more) 04018 return; 04019 04020 /* If there is nothing more to this object, this for loop 04021 * won't do anything. 04022 */ 04023 for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) { 04024 op = arch_to_object(at); 04025 04026 /* update x,y coordinates */ 04027 op->x += tmp->x; 04028 op->y += tmp->y; 04029 op->head = tmp; 04030 op->map = tmp->map; 04031 last->more = op; 04032 if (tmp->name != op->name) { 04033 if (op->name) 04034 free_string(op->name); 04035 op->name = add_string(tmp->name); 04036 } 04037 if (tmp->title != op->title) { 04038 if (op->title) 04039 free_string(op->title); 04040 op->title = add_string(tmp->title); 04041 } 04042 /* we could link all the parts onto tmp, and then just 04043 * call insert_ob_in_map once, but the effect is the same, 04044 * as insert_ob_in_map will call itself with each part, and 04045 * the coding is simpler to just to it here with each part. 04046 */ 04047 insert_ob_in_map(op, op->map, tmp, INS_NO_MERGE|INS_ABOVE_FLOOR_ONLY|INS_NO_WALK_ON); 04048 } /* for at = tmp->arch->more */ 04049 } 04050 04066 void get_multi_size(object *ob, int *sx, int *sy, int *hx, int *hy) { 04067 archetype *part; 04068 int maxx = 0, maxy = 0, minx = 0, miny = 0; 04069 04070 if (ob->head) 04071 ob = ob->head; 04072 *sx = 1; 04073 *sy = 1; 04074 if (ob->arch->more) { 04075 for (part = ob->arch; part; part = part->more) { 04076 if (part->clone.x > maxx) 04077 maxx = part->clone.x; 04078 if (part->clone.y > maxy) 04079 maxy = part->clone.y; 04080 if (part->clone.x < minx) 04081 minx = part->clone.x; 04082 if (part->clone.y < miny) 04083 miny = part->clone.y; 04084 } 04085 } 04086 if (sx) 04087 *sx = maxx; 04088 if (sy) 04089 *sy = maxy; 04090 if (hx) 04091 *hx = -minx; 04092 if (hy) 04093 *hy = -miny; 04094 }