00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034
00035
00036
00037
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <global.h>
00041 #ifndef WIN32
00042 #include <stdio.h>
00043 #include <sys/types.h>
00044 #include <sys/uio.h>
00045 #endif
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
00112
00113
00114
00115
00116
00117 for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next) {
00118 key_value *has_field;
00119
00120
00121 has_field = get_ob_key_link(has, wants_field->key);
00122
00123 if (has_field == NULL) {
00124
00125 return FALSE;
00126 }
00127
00128
00129 if (has_field->value != wants_field->value) {
00130
00131 return FALSE;
00132 }
00133
00134
00135 }
00136
00137
00138 return TRUE;
00139 }
00140
00149 static int compare_ob_value_lists(const object *ob1, const object *ob2) {
00150
00151
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
00181 if ((ob1 == ob2) || (ob1->type != ob2->type))
00182 return 0;
00183
00184 if (ob1->speed != ob2->speed)
00185 return 0;
00186
00187
00188
00189
00190
00191 if (!QUERY_FLAG(ob1, FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
00192 return 0;
00193
00194
00195
00196
00197
00198 if (ob1->nrof+ob2->nrof >= 1UL<<31)
00199 return 0;
00200
00201
00202
00203
00204
00205 if (ob1->inv || ob2->inv) {
00206
00207 if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
00208 return 0;
00209
00210
00211 if (!can_merge(ob1->inv, ob2->inv))
00212 return 0;
00213
00214
00215
00216
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
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
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))
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
00268
00269
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
00276 if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) {
00277
00278 return 0;
00279 } else {
00280 return compare_ob_value_lists(ob1, ob2);
00281 }
00282 }
00283
00284
00285 switch (ob1->type) {
00286 case SCROLL:
00287 if (ob1->level != ob2->level)
00288 return 0;
00289 break;
00290
00291 }
00292
00293
00294 if (ob1->custom_name != ob2->custom_name)
00295 return 0;
00296
00297
00298 return 1;
00299 }
00300
00316
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
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
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
00573
00574
00575
00576
00577
00578
00579 while (owner->owner
00580 && owner != owner->owner
00581 && owner->ownercount == owner->owner->count)
00582 owner = owner->owner;
00583
00584
00585
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
00618
00619
00620
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
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
00691
00692
00693
00694
00695
00696 free_key_values(op);
00697 free_dialog_information(op);
00698
00699
00700
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
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
00719
00720
00721
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
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
00762
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
00778
00779 free_key_values(op);
00780 free_dialog_information(op);
00781
00782
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
00811
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
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
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
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
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
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
01010 extern int arch_init;
01011
01012
01013
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
01029
01030 if (op->active_next || op->active_prev || op == active_objects)
01031 return;
01032
01033
01034
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
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
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
01119 LOG(llevDebug, "update_object() called for NULL object.\n");
01120 return;
01121 }
01122
01123 if (op->env != NULL) {
01124
01125
01126
01127 return;
01128 }
01129
01130
01131
01132
01133 if (!op->map || op->map->in_memory == MAP_SAVING)
01134 return;
01135
01136
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
01171
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
01181
01182
01183
01184 } else if (action == UP_OBJ_REMOVE) {
01185 update_now = 1;
01186 } else if (action == UP_OBJ_FACE || action == UP_OBJ_CHANGE) {
01187
01188
01189
01190 if (action == UP_OBJ_CHANGE)
01191 update_now = 1;
01192
01193
01194
01195
01196
01197
01198
01199
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
01207
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
01292 execute_event(ob, EVENT_DESTROY, NULL, NULL, NULL, SCRIPT_FIX_NOTHING);
01293
01294 if (ob->inv) {
01295
01296
01297
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 {
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
01324 if (ob->more) {
01325 int partcount = 0;
01326
01327 for (part = ob; part; part = part->more) {
01328 partcount++;
01329 }
01330
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);
01349 }
01350 } else {
01351 op->x = part->x;
01352 op->y = part->y;
01353 insert_ob_in_map(op, part->map, NULL, 0);
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
01367 ob->speed = 0;
01368 update_ob_speed(ob);
01369
01370 SET_FLAG(ob, FLAG_FREED);
01371 ob->count = 0;
01372
01373
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
01397 free_key_values(ob);
01398
01399 free_dialog_information(ob);
01400
01401
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
01410
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
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
01541
01542
01543
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
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
01559 pl = op->env->env->contr;
01560 else if (op->env->map) {
01561
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
01574
01575
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
01591
01592
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
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
01625 if (op->above)
01626 op->above->below = op->below;
01627 else
01628 SET_MAP_TOP(m, x, y, op->below);
01629
01630
01631 if (op->below) {
01632 op->below->above = op->above;
01633 } else {
01634
01635
01636
01637
01638
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);
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
01667
01668
01669
01670 if (tmp->type == PLAYER && tmp != op) {
01671
01672
01673
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
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
01691 if (tmp->above == tmp)
01692 tmp->above = NULL;
01693 last = tmp;
01694 }
01695
01696 if (last == NULL) {
01697
01698
01699
01700
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;
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
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
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
01826
01827
01828
01829
01830
01831
01832
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
01845
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
01853
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
01860
01861
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
01869
01870
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
01878
01879
01880
01881
01882 if (i <= SPELL_TAG_SIZE)
01883 continue;
01884
01885
01886
01887
01888
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
01901 if (tmp->spell_tags && !op->spell_tags) {
01902 op->spell_tags = tmp->spell_tags;
01903 tmp->spell_tags = NULL;
01904
01905
01906
01907
01908 if (OB_SPELL_TAG_MATCH(op, op->stats.maxhp))
01909 OB_SPELL_TAG_HASH(op, op->stats.maxhp) = 0;
01910 }
01911
01912
01913
01914
01915
01916
01917 if (op->stats.maxhp != tmp->stats.maxhp) {
01918 #ifdef OBJECT_DEBUG
01919
01920
01921
01922
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
01942
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
01952
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
02022
02023
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
02042
02043 object *more = op->more;
02044
02045
02046
02047
02048
02049
02050 if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) {
02051
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
02057
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
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
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
02096
02097
02098
02099 if (op->map != m) {
02100
02101 op->x = x;
02102 op->y = y;
02103 }
02104
02105 if (op->type != LAMP)
02106
02107
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
02114
02115
02116
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
02135 originator->below = op;
02136 } else {
02137
02138
02139
02140
02141 if (((top = GET_MAP_OB(op->map, op->x, op->y)) != NULL)) {
02142 object *last = NULL;
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
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
02166 top = top->below;
02167 break;
02168 }
02169 last = top;
02170 top = top->above;
02171 }
02172
02173 top = last;
02174
02175
02176
02177
02178
02179
02180 }
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
02187
02188
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 {
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 }
02205
02206 if (op->type == PLAYER)
02207 op->contr->do_los = 1;
02208
02209
02210
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
02219
02220
02221
02222
02223
02224
02225
02226
02227 if (MAP_DARKNESS(op->map) && (op->glow_radius != 0))
02228 update_all_los(op->map, op->x, op->y);
02229
02230
02231
02232 update_object(op, UP_OBJ_INSERT);
02233
02234 if (op->contr && !op->contr->hidden)
02235 op->map->players++;
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248 if (!(flag&INS_NO_WALK_ON) && !op->head) {
02249 if (check_move_on(op, originator))
02250 return NULL;
02251
02252
02253
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
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)) {
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
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)
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
02359
02360
02361 tmp = get_player_container(op->env);
02362
02363
02364
02365
02366
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
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)
02428 return;
02429
02430 if (QUERY_FLAG(op, FLAG_REMOVED)) {
02431 op->nrof += i;
02432 } else if (op->env != NULL) {
02433
02434
02435
02436 tmp = get_player_container(op->env);
02437
02438
02439
02440
02441
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
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
02550
02551 increase_ob_nr(tmp, op->nrof);
02552 SET_FLAG(op, FLAG_REMOVED);
02553 free_object(op);
02554 return tmp;
02555 }
02556
02557
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
02572
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
02583
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
02591 pl = op->env->env;
02592 else if (op->env->map) {
02593
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
02610
02611 fix_object(otmp);
02612 }
02613
02614
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
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
02668
02669
02670
02671
02672 if (op->move_type
02673 && !(op->move_type&move_on)
02674 && !(op->move_type&move_slow))
02675 return 0;
02676
02677
02678
02679
02680
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
02687
02688
02689
02690 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) {
02691
02692
02693
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;
02701
02702
02703
02704
02705
02706
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
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
02733
02734
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
02946
02947
02948
02949
02950
02951 sx++;
02952 sy++;
02953 genx++;
02954 geny++;
02955
02956
02957
02958
02959
02960 ix = gen->x-sx-genx2;
02961 iy = gen->y-sy-geny2;
02962 sx += genx+sx2;
02963 sy += geny+sy2;
02964
02965
02966
02967
02968
02969
02970
02971
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
02988 flag = ob_blocked(ob, gen->map, nx, ny);
02989 if (!flag) {
02990 freecount++;
02991 }
02992 }
02993
02994 if (!freecount)
02995 return -1;
02996
02997
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
03015 if (nx < 0 || nx >= MAP_WIDTH(gen->map)
03016 || ny < 0 || ny >= MAP_HEIGHT(gen->map))
03017 continue;
03018
03019
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
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
03078
03079
03080
03081
03082
03083
03084
03085
03086
03087 sx++;
03088 sy++;
03089 genx++;
03090 geny++;
03091
03092
03093
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
03103
03104
03105
03106
03107
03108
03109 x_array = malloc(sx*sy*sizeof(sint8));
03110 y_array = malloc(sx*sy*sizeof(sint8));
03111
03112
03113
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
03122 if (get_map_flags(gen->map, NULL, nx, ny, NULL, NULL)&P_OUT_OF_MAP) {
03123 continue;
03124 }
03125
03126
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
03136 if (!freecount) {
03137 free(x_array);
03138 free(y_array);
03139 return -1;
03140 }
03141
03142
03143 freecountstop = RANDOM()%freecount;
03144 for (i = 0; i < freecount; i++) {
03145 nx = x_array[i];
03146 ny = y_array[i];
03147
03148
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
03210
03211
03212
03213
03214
03215
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
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 },
03456 { 0, 0, 0 },
03457 { 0, 0, 0 },
03458 { 0, 0, 0 },
03459 { 0, 0, 0 },
03460 { 0, 0, 0 },
03461 { 0, 0, 0 },
03462 { 0, 0, 0 },
03463 { 0, 0, 0 },
03464 { 8, 1, 2 },
03465 { 1, 2, -1 },
03466 { 2, 10, 12 },
03467 { 2, 3, -1 },
03468 { 2, 3, 4 },
03469 { 3, 4, -1 },
03470 { 4, 14, 16 },
03471 { 5, 4, -1 },
03472 { 4, 5, 6 },
03473 { 6, 5, -1 },
03474 { 6, 20, 18 },
03475 { 7, 6, -1 },
03476 { 6, 7, 8 },
03477 { 7, 8, -1 },
03478 { 8, 22, 24 },
03479 { 8, 1, -1 },
03480 { 24, 9, 10 },
03481 { 9, 10, -1 },
03482 { 10, 11, -1 },
03483 { 27, 11, 29 },
03484 { 11, 12, -1 },
03485 { 12, 13, -1 },
03486 { 12, 13, 14 },
03487 { 13, 14, -1 },
03488 { 14, 15, -1 },
03489 { 33, 15, 35 },
03490 { 16, 15, -1 },
03491 { 17, 16, -1 },
03492 { 18, 17, 16 },
03493 { 18, 17, -1 },
03494 { 18, 19, -1 },
03495 { 41, 19, 39 },
03496 { 19, 20, -1 },
03497 { 20, 21, -1 },
03498 { 20, 21, 22 },
03499 { 21, 22, -1 },
03500 { 23, 22, -1 },
03501 { 45, 47, 23 },
03502 { 23, 24, -1 },
03503 { 24, 9, -1 }
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;
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
03537
03538
03539
03540
03541
03542
03543 if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
03544 return 0;
03545
03546
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
03571
03572
03573
03574
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
03586 if (who->type != PLAYER && item->weight > (who->weight/3))
03587 return 0;
03588
03589
03590 if (item->head || item->more)
03591 return 0;
03592
03593
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
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
03709
03710
03711
03712
03713 return NULL;
03714 }
03715
03716
03717
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
03758
03759
03760
03761
03762 if (get_ob_key_link(&op->arch->clone, canonical_key))
03763 field->value = NULL;
03764 else {
03765
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
03780
03781
03782
03783 if (!add_key) {
03784 return FALSE;
03785 }
03786
03787
03788
03789
03790
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
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
03832
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);
03905
03906 for (cp = strtok(local_name, ","); cp; cp = strtok(NULL, ",")) {
03907 while (cp[0] == ' ')
03908 ++cp;
03909
03910
03911
03912 if (!strcmp(cp, "all"))
03913 return 1;
03914
03915
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
03927 if ((count = atoi(cp)) != 0) {
03928 cp = strchr(cp, ' ');
03929 while (cp && cp[0] == ' ')
03930 ++cp;
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
03942
03943
03944
03945
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
03967
03968
03969
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
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
03984 else if (strcasecmp(cp, op->name) == 0 && !count)
03985 retval = 4;
03986
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
04017 if (tmp->head || tmp->more)
04018 return;
04019
04020
04021
04022
04023 for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
04024 op = arch_to_object(at);
04025
04026
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
04043
04044
04045
04046
04047 insert_ob_in_map(op, op->map, tmp, INS_NO_MERGE|INS_ABOVE_FLOOR_ONLY|INS_NO_WALK_ON);
04048 }
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 }